Skip to content

Commit

Permalink
optimisations for embedded use
Browse files Browse the repository at this point in the history
less heap allocations
  • Loading branch information
ysoldak committed Jul 28, 2024
1 parent 2390a19 commit 17ca46b
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 26 deletions.
26 changes: 14 additions & 12 deletions adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,22 @@ type Adapter struct {
func NewAdapter(wire io.ReadWriter) *Adapter {
return &Adapter{
wire: wire,
message: Message{
Payload: []byte{},
},
}
}

// Send a message.
func (a *Adapter) Send(message *Message) error {
bytes := message.Bytes()
bytes := make([]byte, 5+maxPayload+1) // optimisation to avoid heap allocation: could allocate only required size, but that is not constant
_ = message.Bytes(bytes)
logTs("SEND ")
for _, b := range bytes {
log(" %02X", b)
}
log("\n")
n, err := a.wire.Write(bytes)
n, err := a.wire.Write(bytes[0:message.Size()])
if err != nil {
return ErrWrite
}
Expand All @@ -61,12 +65,12 @@ func (a *Adapter) Send(message *Message) error {
}

// Receive a message; returns nil if no message is available (yet).
func (a *Adapter) Receive() (*Message, error) {
func (a *Adapter) Receive(result *Message) error {
buf := make([]byte, 16)
for {
n, err := a.wire.Read(buf)
if err != nil || n == 0 {
return nil, ErrNoData
return ErrNoData
}
for i := 0; i < n; i++ {
b := buf[i]
Expand Down Expand Up @@ -100,7 +104,7 @@ func (a *Adapter) Receive() (*Message, error) {
continue
}
a.message.Length = b
a.message.Payload = []byte{}
a.message.Payload = a.message.Payload[:0]
a.message.Checksum = b
a.state = stateCommand
case stateCommand:
Expand All @@ -116,19 +120,18 @@ func (a *Adapter) Receive() (*Message, error) {
}
case stateChecksum:
logTs("PAYLOAD ")
for _, bb := range a.message.Bytes() {
for _, bb := range a.message.Payload {
log(" %02X", bb)
}
log("\n")
logTs("CHECKSUM expected %02X ?= %02X actual\n", a.message.Checksum, b)
result := a.message
a.message = Message{}
result.Copy(&a.message)
a.state = stateIdle
if result.Checksum == b {
a.handleBeaconMaybe(&result)
return &result, nil
a.handleBeaconMaybe(result)
return nil
} else {
return nil, ErrWrongChecksum
return ErrWrongChecksum
}
}
}
Expand All @@ -138,7 +141,6 @@ func (a *Adapter) Receive() (*Message, error) {
// Reset the state machine and clear the message buffer.
func (a *Adapter) Reset() {
a.state = stateIdle
a.message = Message{}
buf := make([]byte, 16)
for {
n, err := a.wire.Read(buf)
Expand Down
13 changes: 8 additions & 5 deletions adapter_avr.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
package csp

// Wait for a message with the given command and direction.
func (a *Adapter) Wait(command Command, direction Direction, timeout int64) (*Message, error) {
func (a *Adapter) Wait(command Command, direction Direction, timeout int64, message *Message) error {
start := runtime_nanotime()
for runtime_nanotime()-start < timeout {
message, _ := a.Receive()
err := a.Receive(message)
if err != nil {
continue
}
// wait for correct message
if message != nil && message.Command == command && message.Direction == direction {
return message, nil
if message.Command == command && message.Direction == direction {
return nil
}
}
return nil, ErrTimeout
return ErrTimeout
}

// BeaconTime returns the next time when a beacon with the given ID should be broadcasted.
Expand Down
13 changes: 8 additions & 5 deletions adapter_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ package csp
import "time"

// Wait for a message with the given command and direction.
func (a *Adapter) Wait(command Command, direction Direction, timeout time.Duration) (*Message, error) {
func (a *Adapter) Wait(command Command, direction Direction, timeout time.Duration, message *Message) error {
start := time.Now()
for time.Since(start) < timeout {
message, _ := a.Receive()
err := a.Receive(message)
if err != nil {
continue
}
// wait for correct message
if message != nil && message.Command == command && message.Direction == direction {
return message, nil
if message.Command == command && message.Direction == direction {
return nil
}
}
return nil, ErrTimeout
return ErrTimeout
}

// BeaconTime returns the next time when a beacon with the given ID should be broadcasted.
Expand Down
30 changes: 26 additions & 4 deletions message.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package csp

import "errors"

// Commands
type Command byte

Expand All @@ -20,6 +22,8 @@ const (
CmdHit Command = 0x82
)

var errBufferTooSmall = errors.New("buffer too small")

// Directions
type Direction byte

Expand Down Expand Up @@ -64,16 +68,34 @@ func NewMessage(direction Direction, command Command, data []byte) *Message {
}
}

func (m *Message) Bytes() []byte {
b := make([]byte, 5+len(m.Payload)+1)
func (m *Message) Copy(o *Message) {
copy(m.Header[:], o.Header[:])
m.Direction = o.Direction
m.Length = o.Length
m.Command = o.Command
if m.Payload == nil {
m.Payload = make([]byte, o.Length)
}
copy(m.Payload, o.Payload)
m.Checksum = o.Checksum
}

func (m *Message) Bytes(b []byte) error {
if len(b) < int(m.Size()) {
return errBufferTooSmall
}
b[0] = m.Header[0]
b[1] = m.Header[1]
b[2] = byte(m.Direction)
b[3] = m.Length
b[4] = byte(m.Command)
copy(b[5:], m.Payload)
b[len(b)-1] = m.Checksum
return b
b[m.Size()-1] = m.Checksum
return nil
}

func (m *Message) Size() byte {
return 5 + m.Length + 1
}

func (m *Message) IsRequest() bool {
Expand Down

0 comments on commit 17ca46b

Please sign in to comment.