Skip to content

Commit

Permalink
feat(emulator): take in options as an optional argument
Browse files Browse the repository at this point in the history
  • Loading branch information
felixmr1 committed Nov 28, 2022
1 parent 4c717a0 commit 0787432
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 56 deletions.
12 changes: 10 additions & 2 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,21 @@ func TestUDPEmulator(t *testing.T) {

timeout := 100 * time.Millisecond

connEmulator, err := xsensemulator.NewUDPSerialPort(addrEmulator, addrClient, timeout)
connEmulator, err := xsensemulator.NewUDPSerialPort(
addrEmulator,
addrClient,
xsensemulator.WithTimeout(timeout),
)
assert.NilError(t, err)
defer func() {
assert.NilError(t, connEmulator.Close())
}()

connClient, err := xsensemulator.NewUDPSerialPort(addrClient, addrEmulator, timeout)
connClient, err := xsensemulator.NewUDPSerialPort(
addrClient,
addrEmulator,
xsensemulator.WithTimeout(timeout),
)
assert.NilError(t, err)

emu := xsensemulator.NewEmulator(connEmulator)
Expand Down
60 changes: 7 additions & 53 deletions xsensemulator/emulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import (
"errors"
"fmt"
"io"
"net"
"sync"
"time"

"go.einride.tech/xsens"
)
Expand All @@ -18,55 +16,6 @@ var (
ErrNotInOutputConfiguration = errors.New("not in output configuration")
)

type UDPSerialPort struct {
io.ReadWriteCloser
// Timeout for setting read/write deadlines
timeout time.Duration
OriginConn *net.UDPConn
DestinationAddr *net.UDPAddr
}

func NewUDPSerialPort(origin, destination string, timeout time.Duration) (*UDPSerialPort, error) {
udpOriginAddr, err := net.ResolveUDPAddr("udp", origin)
if err != nil {
return nil, fmt.Errorf("new udp serial port: %w", err)
}
udpDestinationAddr, err := net.ResolveUDPAddr("udp", destination)
if err != nil {
return nil, fmt.Errorf("new udp serial port: %w", err)
}
originConn, err := net.ListenUDP("udp", udpOriginAddr)
if err != nil {
return nil, fmt.Errorf("new udp serial port: %w", err)
}
return &UDPSerialPort{
OriginConn: originConn,
DestinationAddr: udpDestinationAddr,
timeout: timeout,
}, nil
}

func (t UDPSerialPort) Read(p []byte) (n int, err error) {
err = t.OriginConn.SetReadDeadline(time.Now().Add(t.timeout))
if err != nil {
return 0, fmt.Errorf("udp serial port read: %w", err)
}
n, _, err = t.OriginConn.ReadFromUDP(p)
return n, err
}

func (t UDPSerialPort) Write(p []byte) (n int, err error) {
err = t.OriginConn.SetWriteDeadline(time.Now().Add(t.timeout))
if err != nil {
return 0, fmt.Errorf("udp serial port write: %w", err)
}
return t.OriginConn.WriteToUDP(p, t.DestinationAddr)
}

func (t UDPSerialPort) Close() error {
return t.OriginConn.Close()
}

type Emulator struct {
port io.ReadWriteCloser
w *bufio.Writer
Expand Down Expand Up @@ -139,7 +88,9 @@ func (e *Emulator) Receive(ctx context.Context) error {
e.mutex.Lock()
e.lastMessageIdentifier = xsens.MessageIdentifierSetOutputConfiguration
e.mutex.Unlock()
_, err := e.port.Write(xsens.NewMessage(xsens.MessageIdentifierSetOutputConfigurationAck, nil))
_, err := e.port.Write(
xsens.NewMessage(xsens.MessageIdentifierSetOutputConfigurationAck, nil),
)
if err != nil {
return fmt.Errorf("receive: %w", err)
}
Expand Down Expand Up @@ -168,7 +119,10 @@ func (e *Emulator) Transmit(m xsens.Message) error {
return nil
}

func (e *Emulator) MarshalMessage(measurement xsens.MeasurementData, dataType xsens.DataType) ([]byte, error) {
func (e *Emulator) MarshalMessage(
measurement xsens.MeasurementData,
dataType xsens.DataType,
) ([]byte, error) {
var id xsens.DataIdentifier
var isSet bool
for _, d := range e.outputConf {
Expand Down
5 changes: 4 additions & 1 deletion xsensemulator/emulator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,10 @@ func TestEmulator_Output(t *testing.T) {
}
packets := []byte{}
for client.ScanMeasurementData() {
m, err := emulator.MarshalMessage(client.MeasurementData(), client.DataType())
m, err := emulator.MarshalMessage(
client.MeasurementData(),
client.DataType(),
)
assert.NilError(t, err)
packets = append(packets, m...)
}
Expand Down
91 changes: 91 additions & 0 deletions xsensemulator/udpserialport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package xsensemulator

import (
"fmt"
"io"
"net"
"time"
)

type UDPSerialPort struct {
io.ReadWriteCloser
opts *udpSerialPortOptions
OriginConn *net.UDPConn
DestinationAddr *net.UDPAddr
}

func NewUDPSerialPort(
origin string,
destination string,
udpSerialOpts ...UDPSerialPortOption,
) (*UDPSerialPort, error) {
opts := defaultOptions()
for _, udpSerialOpt := range udpSerialOpts {
udpSerialOpt(opts)
}

udpOriginAddr, err := net.ResolveUDPAddr("udp", origin)
if err != nil {
return nil, fmt.Errorf("new udp serial port: %w", err)
}
udpDestinationAddr, err := net.ResolveUDPAddr("udp", destination)
if err != nil {
return nil, fmt.Errorf("new udp serial port: %w", err)
}
originConn, err := net.ListenUDP("udp", udpOriginAddr)
if err != nil {
return nil, fmt.Errorf("new udp serial port: %w", err)
}
return &UDPSerialPort{
opts: opts,
OriginConn: originConn,
DestinationAddr: udpDestinationAddr,
}, nil
}

func (t UDPSerialPort) Read(p []byte) (n int, err error) {
// Check if a timeout opts have been added
if t.opts.timeout != time.Duration(0) {
err = t.OriginConn.SetReadDeadline(time.Now().Add(t.opts.timeout))
if err != nil {
return 0, fmt.Errorf("udp serial port read: %w", err)
}
}
n, _, err = t.OriginConn.ReadFromUDP(p)
return n, err
}

func (t UDPSerialPort) Write(p []byte) (n int, err error) {
// Check if a timeout opts have been added
if t.opts.timeout != time.Duration(0) {
err = t.OriginConn.SetWriteDeadline(time.Now().Add(t.opts.timeout))
if err != nil {
return 0, fmt.Errorf("udp serial port write: %w", err)
}
}
return t.OriginConn.WriteToUDP(p, t.DestinationAddr)
}

func (t UDPSerialPort) Close() error {
return t.OriginConn.Close()
}

type udpSerialPortOptions struct {
// Timeout for setting read/write deadlines
timeout time.Duration
}

// defaultOptions returns udpSerialPortOptions with sensible default values.
func defaultOptions() *udpSerialPortOptions {
return &udpSerialPortOptions{}
}

// UDPSerialPortOption configures an UDPSerialPort.
type UDPSerialPortOption func(*udpSerialPortOptions)

// WithTransmitInterface configures the interface to transmit on.
func WithTimeout(timeout time.Duration) UDPSerialPortOption {
return func(opt *udpSerialPortOptions) {
opt.timeout = timeout
}
}

0 comments on commit 0787432

Please sign in to comment.