move device string parsing to xbee library

This commit is contained in:
saji 2023-05-08 18:32:22 -05:00
parent cf21deed1b
commit 2b7426903a
2 changed files with 89 additions and 75 deletions

View file

@ -5,18 +5,12 @@ package cli
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"net"
"os" "os"
"runtime"
"strconv"
"strings"
"github.com/kschamplin/gotelem/xbee" "github.com/kschamplin/gotelem/xbee"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"go.bug.st/serial"
"golang.org/x/exp/slog" "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. // this parses the device string and creates the io device.
// TODO: should we create the session here instead? // TODO: should we create the session here instead?
Before: func(ctx *cli.Context) error { Before: func(ctx *cli.Context) error {
transport, err := parseDeviceString(ctx.String("device")) transport, err := xbee.ParseDeviceString(ctx.String("device"))
if err != nil { if err != nil {
return err return err
} }
@ -91,7 +85,7 @@ writtend to stdout.
func xbeeInfo(ctx *cli.Context) error { func xbeeInfo(ctx *cli.Context) error {
logger := slog.New(slog.NewTextHandler(os.Stderr)) 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())) xb, err := xbee.NewSession(transport, logger.With("device", transport.Type()))
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
@ -115,7 +109,7 @@ func netcat(ctx *cli.Context) error {
} }
logger := slog.New(slog.NewTextHandler(os.Stderr)) 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())) xb, _ := xbee.NewSession(transport, logger.With("devtype", transport.Type()))
sent := make(chan int64) sent := make(chan int64)
@ -139,69 +133,3 @@ func netcat(ctx *cli.Context) error {
return nil 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
}

View file

@ -12,8 +12,14 @@ import (
"fmt" "fmt"
"io" "io"
"sync" "sync"
"strings"
"errors"
"runtime"
"net"
"strconv"
"golang.org/x/exp/slog" "golang.org/x/exp/slog"
"go.bug.st/serial"
) )
// TODO: implement net.Conn for Session/Conn. We are missing LocalAddr, RemoteAddr, // 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) { func (c *Conn) Write(p []byte) (int, error) {
return c.parent.writeAddr(p, c.addr) 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
}