From 2b7426903aef23cd786cc88f70421e1483f846e7 Mon Sep 17 00:00:00 2001 From: saji <9110284+kschamplin@users.noreply.github.com> Date: Mon, 8 May 2023 18:32:22 -0500 Subject: [PATCH] move device string parsing to xbee library --- cmd/gotelem/cli/xbee.go | 78 ++----------------------------------- xbee/session.go | 86 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 75 deletions(-) diff --git a/cmd/gotelem/cli/xbee.go b/cmd/gotelem/cli/xbee.go index 104dc56..408fba1 100644 --- a/cmd/gotelem/cli/xbee.go +++ b/cmd/gotelem/cli/xbee.go @@ -5,18 +5,12 @@ package cli import ( "context" - "errors" "fmt" "io" - "net" "os" - "runtime" - "strconv" - "strings" "github.com/kschamplin/gotelem/xbee" "github.com/urfave/cli/v2" - "go.bug.st/serial" "golang.org/x/exp/slog" ) @@ -56,7 +50,7 @@ TCP/UDP connections require a port and will fail if one is not provided. // this parses the device string and creates the io device. // TODO: should we create the session here instead? Before: func(ctx *cli.Context) error { - transport, err := parseDeviceString(ctx.String("device")) + transport, err := xbee.ParseDeviceString(ctx.String("device")) if err != nil { return err } @@ -91,7 +85,7 @@ writtend to stdout. func xbeeInfo(ctx *cli.Context) error { logger := slog.New(slog.NewTextHandler(os.Stderr)) - transport := ctx.Context.Value(keyIODevice).(xbeeTransport) + transport := ctx.Context.Value(keyIODevice).(xbee.Transport) xb, err := xbee.NewSession(transport, logger.With("device", transport.Type())) if err != nil { return cli.Exit(err, 1) @@ -115,7 +109,7 @@ func netcat(ctx *cli.Context) error { } logger := slog.New(slog.NewTextHandler(os.Stderr)) - transport := ctx.Context.Value(keyIODevice).(xbeeTransport) + transport := ctx.Context.Value(keyIODevice).(xbee.Transport) xb, _ := xbee.NewSession(transport, logger.With("devtype", transport.Type())) sent := make(chan int64) @@ -139,69 +133,3 @@ func netcat(ctx *cli.Context) error { return nil } -type xbeeTransport struct { - io.ReadWriteCloser - devType string -} - -func (xbt *xbeeTransport) Type() string { - return xbt.devType -} - -// parseDeviceString parses the device parameter and sets up the associated -// device. The device is returned in an xbeeTransport which also stores -// the underlying type of the device with Type() string -func parseDeviceString(dev string) (*xbeeTransport, error) { - xbt := &xbeeTransport{} - - parseSerial := func(s string) (serial.Port, error) { - - path, bRate, found := strings.Cut(dev, ":") - - mode := &serial.Mode{ - BaudRate: 9600, - } - if found { - b, err := strconv.Atoi(bRate) - if err != nil { - return nil, err - } - mode.BaudRate = b - } - return serial.Open(path, mode) - } - - // actually parse the path - if strings.HasPrefix(dev, "tcp://") { - - addr, _ := strings.CutPrefix(dev, "tcp://") - - conn, err := net.Dial("tcp", addr) - if err != nil { - return nil, err - } - xbt.ReadWriteCloser = conn - - xbt.devType = "tcp" - - } else if strings.HasPrefix(dev, "COM") && runtime.GOOS == "windows" { - - sDev, err := parseSerial(dev) - if err != nil { - return nil, err - } - xbt.ReadWriteCloser = sDev - xbt.devType = "serialWin" - - } else if strings.HasPrefix(dev, "/") && runtime.GOOS != "windows" { - sDev, err := parseSerial(dev) - if err != nil { - return nil, err - } - xbt.ReadWriteCloser = sDev - xbt.devType = "serial" - } else { - return nil, errors.New("could not parse device path") - } - return xbt, nil -} diff --git a/xbee/session.go b/xbee/session.go index edcd00b..0a349b5 100644 --- a/xbee/session.go +++ b/xbee/session.go @@ -12,8 +12,14 @@ import ( "fmt" "io" "sync" + "strings" + "errors" + "runtime" + "net" + "strconv" "golang.org/x/exp/slog" + "go.bug.st/serial" ) // TODO: implement net.Conn for Session/Conn. We are missing LocalAddr, RemoteAddr, @@ -232,3 +238,83 @@ type Conn struct { func (c *Conn) Write(p []byte) (int, error) { return c.parent.writeAddr(p, c.addr) } + + + +/* Transport represents a connection that an XBee can use. + it's mostly a helper struct to parse URIs. It can parse the following formats: + + tcp://192.168.4.5:8340 + COM1 + /dev/ttyUSB0:115200 + +for network devices, a port is optional. If it is not specified it will +default to 2616. The colon after a serial port sets the baud rate. +It will default to 9600 if not specified. +*/ +type Transport struct { + io.ReadWriteCloser + devType string +} + +func (xbt *Transport) Type() string { + return xbt.devType +} + +// parseDeviceString parses the device parameter and sets up the associated +// device. The device is returned in an xbeeTransport which also stores +// the underlying type of the device with Type() string +func ParseDeviceString(dev string) (*Transport, error) { + xbt := &Transport{} + + parseSerial := func(s string) (serial.Port, error) { + + path, bRate, found := strings.Cut(dev, ":") + + mode := &serial.Mode{ + BaudRate: 9600, + } + if found { + b, err := strconv.Atoi(bRate) + if err != nil { + return nil, err + } + mode.BaudRate = b + } + return serial.Open(path, mode) + } + + // actually parse the path + if strings.HasPrefix(dev, "tcp://") { + + addr, _ := strings.CutPrefix(dev, "tcp://") + + conn, err := net.Dial("tcp", addr) + if err != nil { + return nil, err + } + xbt.ReadWriteCloser = conn + + xbt.devType = "tcp" + + } else if strings.HasPrefix(dev, "COM") && runtime.GOOS == "windows" { + + sDev, err := parseSerial(dev) + if err != nil { + return nil, err + } + xbt.ReadWriteCloser = sDev + xbt.devType = "serialWin" + + } else if strings.HasPrefix(dev, "/") && runtime.GOOS != "windows" { + sDev, err := parseSerial(dev) + if err != nil { + return nil, err + } + xbt.ReadWriteCloser = sDev + xbt.devType = "serial" + } else { + return nil, errors.New("could not parse device path") + } + return xbt, nil +}