mess around with a sort node concept for communicating over packet RF things
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
module node
|
||||||
|
|
||||||
|
go 1.26.2
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
id NodeId
|
||||||
|
transport Transport
|
||||||
|
sequenceNumber uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(id NodeId, transport Transport) *Node {
|
||||||
|
return &Node{
|
||||||
|
id: id,
|
||||||
|
transport: transport,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeId uint8
|
||||||
|
|
||||||
|
func (id NodeId) IsBroadcast() bool {
|
||||||
|
return id == 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Node) Receive(timeout uint32) (NodeId, uint32, []byte, error) {
|
||||||
|
data, err := b.transport.Rx(timeout)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, nil, err
|
||||||
|
}
|
||||||
|
if len(data) < 6 {
|
||||||
|
return 0, 0, nil, errors.New("invalid message length")
|
||||||
|
}
|
||||||
|
sourceId := NodeId(data[0])
|
||||||
|
targetId := NodeId(data[1])
|
||||||
|
if targetId != b.id && !targetId.IsBroadcast() {
|
||||||
|
return 0, 0, nil, nil
|
||||||
|
}
|
||||||
|
seq := uint32(data[2])<<24 | uint32(data[3])<<16 | uint32(data[4])<<8 | uint32(data[5])
|
||||||
|
payload := data[6:]
|
||||||
|
return sourceId, seq, payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Node) ReceiveWithAck(timeout uint32) (NodeId, uint32, []byte, error) {
|
||||||
|
data, err := b.transport.Rx(timeout)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, nil, err
|
||||||
|
}
|
||||||
|
if len(data) < 6 {
|
||||||
|
return 0, 0, nil, errors.New("invalid message length")
|
||||||
|
}
|
||||||
|
sourceId := NodeId(data[0])
|
||||||
|
targetId := NodeId(data[1])
|
||||||
|
if targetId != b.id && !targetId.IsBroadcast() {
|
||||||
|
return 0, 0, nil, errors.New("message not intended for this node")
|
||||||
|
}
|
||||||
|
seq := uint32(data[2])<<24 | uint32(data[3])<<16 | uint32(data[4])<<8 | uint32(data[5])
|
||||||
|
payload := data[6:]
|
||||||
|
ackMsg := make([]byte, 6)
|
||||||
|
ackMsg[0] = byte(b.id)
|
||||||
|
ackMsg[1] = byte(sourceId)
|
||||||
|
ackMsg[2] = byte(seq >> 24)
|
||||||
|
ackMsg[3] = byte(seq >> 16)
|
||||||
|
ackMsg[4] = byte(seq >> 8)
|
||||||
|
ackMsg[5] = byte(seq)
|
||||||
|
err = b.transport.Tx(ackMsg, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, nil, err
|
||||||
|
}
|
||||||
|
return sourceId, seq, payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Node) SendWithAck(target NodeId, payload []byte, timeout uint32) error {
|
||||||
|
if target.IsBroadcast() {
|
||||||
|
return errors.New("cannot send with ack to broadcast address")
|
||||||
|
}
|
||||||
|
msg := make([]byte, 6)
|
||||||
|
msg[0] = byte(b.id)
|
||||||
|
msg[1] = byte(target)
|
||||||
|
sentSeq := b.sequenceNumber
|
||||||
|
msg[2] = byte(sentSeq >> 24)
|
||||||
|
msg[3] = byte(sentSeq >> 16)
|
||||||
|
msg[4] = byte(sentSeq >> 8)
|
||||||
|
msg[5] = byte(sentSeq)
|
||||||
|
b.sequenceNumber++
|
||||||
|
msg = append(msg, payload...)
|
||||||
|
b.transport.Tx(msg, timeout)
|
||||||
|
|
||||||
|
sender, receivedSeq, _, err := b.Receive(timeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if sender != target {
|
||||||
|
return errors.New("received ACK from unexpected sender")
|
||||||
|
}
|
||||||
|
if receivedSeq != sentSeq {
|
||||||
|
return errors.New("received ACK with unexpected sequence number")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
type Transport interface {
|
||||||
|
Tx(payload []byte, timeout uint32) error
|
||||||
|
Rx(timeout uint32) ([]byte, error)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user