move tihngs
This commit is contained in:
parent
ba288f2959
commit
c7cda9db7a
|
@ -1,11 +1,69 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kschamplin/gotelem/internal/gotelem"
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const xbeeCategory = "XBee settings"
|
||||||
|
|
||||||
var serveCmd = &cli.Command{
|
var serveCmd = &cli.Command{
|
||||||
Name: "serve",
|
Name: "serve",
|
||||||
Aliases: []string{"server", "s"},
|
Aliases: []string{"server", "s"},
|
||||||
Usage: "Start a telemetry server",
|
Usage: "Start a telemetry server",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{Name: "xbee", Aliases: []string{"x"}, Usage: "Find and connect to an XBee"},
|
||||||
|
},
|
||||||
|
Action: func(ctx *cli.Context) error {
|
||||||
|
serve()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type session struct {
|
||||||
|
conn net.Conn
|
||||||
|
send chan gotelem.Body
|
||||||
|
recv chan gotelem.Body
|
||||||
|
quit chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func serve() {
|
||||||
|
ln, err := net.Listen("tcp", ":8082")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error listening: %v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Listening on :8082\n")
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error accepting: %v\n", err)
|
||||||
|
}
|
||||||
|
go handleCon(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleCon(conn net.Conn) {
|
||||||
|
// reader := msgp.NewReader(conn)
|
||||||
|
writer := msgp.NewWriter(conn)
|
||||||
|
for {
|
||||||
|
// data := telemnet.StatusBody{
|
||||||
|
// BatteryPct: 1.2,
|
||||||
|
// ErrCode: 0,
|
||||||
|
// }
|
||||||
|
// data.EncodeMsg(writer)
|
||||||
|
data := gotelem.StatusBody{
|
||||||
|
BatteryPct: 1.2,
|
||||||
|
ErrCode: 0,
|
||||||
|
}
|
||||||
|
data.EncodeMsg(writer)
|
||||||
|
writer.Flush()
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -9,6 +9,10 @@ require (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
|
github.com/philhofer/fwd v1.1.2 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/tinylib/msgp v1.1.8 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
|
golang.org/x/mod v0.10.0 // indirect
|
||||||
|
golang.org/x/tools v0.8.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
38
go.sum
38
go.sum
|
@ -1,10 +1,48 @@
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
|
||||||
|
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
|
||||||
|
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
|
||||||
github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
|
github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
|
||||||
github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||||
|
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||||
|
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
||||||
|
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
|
@ -29,3 +29,8 @@ type CanSink interface {
|
||||||
type CanSource interface {
|
type CanSource interface {
|
||||||
Recv() (*Frame, error)
|
Recv() (*Frame, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CanTransciever interface {
|
||||||
|
CanSink
|
||||||
|
CanSource
|
||||||
|
}
|
26
internal/can/frame_kind.go
Normal file
26
internal/can/frame_kind.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Code generated by "stringer -output=frame_kind.go -type Kind"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package can
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[SFF-0]
|
||||||
|
_ = x[EFF-1]
|
||||||
|
_ = x[RTR-2]
|
||||||
|
_ = x[ERR-3]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _Kind_name = "SFFEFFRTRERR"
|
||||||
|
|
||||||
|
var _Kind_index = [...]uint8{0, 3, 6, 9, 12}
|
||||||
|
|
||||||
|
func (i Kind) String() string {
|
||||||
|
if i >= Kind(len(_Kind_index)-1) {
|
||||||
|
return "Kind(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||||
|
}
|
||||||
|
return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
|
||||||
|
}
|
21
internal/db/can_adapter.go
Normal file
21
internal/db/can_adapter.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/kschamplin/gotelem/internal/can"
|
||||||
|
)
|
||||||
|
|
||||||
|
// this file implements a CAN adapter for the sqlite db.
|
||||||
|
|
||||||
|
type CanDB struct {
|
||||||
|
Db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cdb *CanDB) Send(_ *can.Frame) error {
|
||||||
|
panic("not implemented") // TODO: Implement
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cdb *CanDB) Recv() (*can.Frame, error) {
|
||||||
|
panic("not implemented") // TODO: Implement
|
||||||
|
}
|
60
internal/gotelem/messages.go
Normal file
60
internal/gotelem/messages.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package gotelem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// a body is a thing that can get a type, which we put in the header.
|
||||||
|
// we use the header to store metadata too
|
||||||
|
type Body interface {
|
||||||
|
GetType() string
|
||||||
|
msgp.Marshaler
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate msgp
|
||||||
|
type Data struct {
|
||||||
|
Header map[string]string `msg:"header"`
|
||||||
|
Body msgp.Raw `msg:"body"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CanBody struct {
|
||||||
|
Id uint32 `msg:"id"`
|
||||||
|
Payload []byte `msg:"data"`
|
||||||
|
Source string `msg:"src"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CanBody) GetType() string {
|
||||||
|
return "canp"
|
||||||
|
}
|
||||||
|
|
||||||
|
// A status contains information about the running application.
|
||||||
|
// mainly internal battery percentage.
|
||||||
|
type StatusBody struct {
|
||||||
|
BatteryPct float32 `msg:"batt"`
|
||||||
|
ErrCode int16 `msg:"err"` // 0 is good.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*StatusBody) GetType() string {
|
||||||
|
return "status"
|
||||||
|
}
|
||||||
|
|
||||||
|
// takes anything that has a GetType() string method and packs it up.
|
||||||
|
func NewData(body Body) (*Data, error) {
|
||||||
|
data := &Data{}
|
||||||
|
|
||||||
|
data.Header["type"] = body.GetType()
|
||||||
|
|
||||||
|
// add other metadata here.
|
||||||
|
data.Header["ver"] = "0.0.1"
|
||||||
|
|
||||||
|
data.Header["test"] = "mesg"
|
||||||
|
|
||||||
|
rawBody, err := body.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Body = rawBody
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
491
internal/gotelem/messages_gen.go
Normal file
491
internal/gotelem/messages_gen.go
Normal file
|
@ -0,0 +1,491 @@
|
||||||
|
package gotelem
|
||||||
|
|
||||||
|
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *CanBody) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "id":
|
||||||
|
z.Id, err = dc.ReadUint32()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "data":
|
||||||
|
z.Payload, err = dc.ReadBytes(z.Payload)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "src":
|
||||||
|
z.Source, err = dc.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Source")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *CanBody) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 3
|
||||||
|
// write "id"
|
||||||
|
err = en.Append(0x83, 0xa2, 0x69, 0x64)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteUint32(z.Id)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "data"
|
||||||
|
err = en.Append(0xa4, 0x64, 0x61, 0x74, 0x61)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteBytes(z.Payload)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "src"
|
||||||
|
err = en.Append(0xa3, 0x73, 0x72, 0x63)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteString(z.Source)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Source")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z *CanBody) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 3
|
||||||
|
// string "id"
|
||||||
|
o = append(o, 0x83, 0xa2, 0x69, 0x64)
|
||||||
|
o = msgp.AppendUint32(o, z.Id)
|
||||||
|
// string "data"
|
||||||
|
o = append(o, 0xa4, 0x64, 0x61, 0x74, 0x61)
|
||||||
|
o = msgp.AppendBytes(o, z.Payload)
|
||||||
|
// string "src"
|
||||||
|
o = append(o, 0xa3, 0x73, 0x72, 0x63)
|
||||||
|
o = msgp.AppendString(o, z.Source)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *CanBody) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "id":
|
||||||
|
z.Id, bts, err = msgp.ReadUint32Bytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "data":
|
||||||
|
z.Payload, bts, err = msgp.ReadBytesBytes(bts, z.Payload)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "src":
|
||||||
|
z.Source, bts, err = msgp.ReadStringBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Source")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z *CanBody) Msgsize() (s int) {
|
||||||
|
s = 1 + 3 + msgp.Uint32Size + 5 + msgp.BytesPrefixSize + len(z.Payload) + 4 + msgp.StringPrefixSize + len(z.Source)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *Data) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "header":
|
||||||
|
var zb0002 uint32
|
||||||
|
zb0002, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if z.Header == nil {
|
||||||
|
z.Header = make(map[string]string, zb0002)
|
||||||
|
} else if len(z.Header) > 0 {
|
||||||
|
for key := range z.Header {
|
||||||
|
delete(z.Header, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for zb0002 > 0 {
|
||||||
|
zb0002--
|
||||||
|
var za0001 string
|
||||||
|
var za0002 string
|
||||||
|
za0001, err = dc.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
za0002, err = dc.ReadString()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.Header[za0001] = za0002
|
||||||
|
}
|
||||||
|
case "body":
|
||||||
|
err = z.Body.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *Data) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 2
|
||||||
|
// write "header"
|
||||||
|
err = en.Append(0x82, 0xa6, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteMapHeader(uint32(len(z.Header)))
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for za0001, za0002 := range z.Header {
|
||||||
|
err = en.WriteString(za0001)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteString(za0002)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write "body"
|
||||||
|
err = en.Append(0xa4, 0x62, 0x6f, 0x64, 0x79)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = z.Body.EncodeMsg(en)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z *Data) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 2
|
||||||
|
// string "header"
|
||||||
|
o = append(o, 0x82, 0xa6, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72)
|
||||||
|
o = msgp.AppendMapHeader(o, uint32(len(z.Header)))
|
||||||
|
for za0001, za0002 := range z.Header {
|
||||||
|
o = msgp.AppendString(o, za0001)
|
||||||
|
o = msgp.AppendString(o, za0002)
|
||||||
|
}
|
||||||
|
// string "body"
|
||||||
|
o = append(o, 0xa4, 0x62, 0x6f, 0x64, 0x79)
|
||||||
|
o, err = z.Body.MarshalMsg(o)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *Data) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "header":
|
||||||
|
var zb0002 uint32
|
||||||
|
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if z.Header == nil {
|
||||||
|
z.Header = make(map[string]string, zb0002)
|
||||||
|
} else if len(z.Header) > 0 {
|
||||||
|
for key := range z.Header {
|
||||||
|
delete(z.Header, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for zb0002 > 0 {
|
||||||
|
var za0001 string
|
||||||
|
var za0002 string
|
||||||
|
zb0002--
|
||||||
|
za0001, bts, err = msgp.ReadStringBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
za0002, bts, err = msgp.ReadStringBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Header", za0001)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.Header[za0001] = za0002
|
||||||
|
}
|
||||||
|
case "body":
|
||||||
|
bts, err = z.Body.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "Body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z *Data) Msgsize() (s int) {
|
||||||
|
s = 1 + 7 + msgp.MapHeaderSize
|
||||||
|
if z.Header != nil {
|
||||||
|
for za0001, za0002 := range z.Header {
|
||||||
|
_ = za0002
|
||||||
|
s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s += 5 + z.Body.Msgsize()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *StatusBody) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "batt":
|
||||||
|
z.BatteryPct, err = dc.ReadFloat32()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "BatteryPct")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "err":
|
||||||
|
z.ErrCode, err = dc.ReadInt16()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "ErrCode")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeMsg implements msgp.Encodable
|
||||||
|
func (z StatusBody) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 2
|
||||||
|
// write "batt"
|
||||||
|
err = en.Append(0x82, 0xa4, 0x62, 0x61, 0x74, 0x74)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteFloat32(z.BatteryPct)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "BatteryPct")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "err"
|
||||||
|
err = en.Append(0xa3, 0x65, 0x72, 0x72)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = en.WriteInt16(z.ErrCode)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "ErrCode")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z StatusBody) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 2
|
||||||
|
// string "batt"
|
||||||
|
o = append(o, 0x82, 0xa4, 0x62, 0x61, 0x74, 0x74)
|
||||||
|
o = msgp.AppendFloat32(o, z.BatteryPct)
|
||||||
|
// string "err"
|
||||||
|
o = append(o, 0xa3, 0x65, 0x72, 0x72)
|
||||||
|
o = msgp.AppendInt16(o, z.ErrCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *StatusBody) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zb0001 uint32
|
||||||
|
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zb0001 > 0 {
|
||||||
|
zb0001--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "batt":
|
||||||
|
z.BatteryPct, bts, err = msgp.ReadFloat32Bytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "BatteryPct")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "err":
|
||||||
|
z.ErrCode, bts, err = msgp.ReadInt16Bytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err, "ErrCode")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
err = msgp.WrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z StatusBody) Msgsize() (s int) {
|
||||||
|
s = 1 + 5 + msgp.Float32Size + 4 + msgp.Int16Size
|
||||||
|
return
|
||||||
|
}
|
349
internal/gotelem/messages_gen_test.go
Normal file
349
internal/gotelem/messages_gen_test.go
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
package gotelem
|
||||||
|
|
||||||
|
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMarshalUnmarshalCanBody(t *testing.T) {
|
||||||
|
v := CanBody{}
|
||||||
|
bts, err := v.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
left, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
|
||||||
|
left, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalMsgCanBody(b *testing.B) {
|
||||||
|
v := CanBody{}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.MarshalMsg(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAppendMsgCanBody(b *testing.B) {
|
||||||
|
v := CanBody{}
|
||||||
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshalCanBody(b *testing.B) {
|
||||||
|
v := CanBody{}
|
||||||
|
bts, _ := v.MarshalMsg(nil)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodeCanBody(t *testing.T) {
|
||||||
|
v := CanBody{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecodeCanBody Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := CanBody{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodeCanBody(b *testing.B) {
|
||||||
|
v := CanBody{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeCanBody(b *testing.B) {
|
||||||
|
v := CanBody{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalUnmarshalData(t *testing.T) {
|
||||||
|
v := Data{}
|
||||||
|
bts, err := v.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
left, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
|
||||||
|
left, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalMsgData(b *testing.B) {
|
||||||
|
v := Data{}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.MarshalMsg(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAppendMsgData(b *testing.B) {
|
||||||
|
v := Data{}
|
||||||
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshalData(b *testing.B) {
|
||||||
|
v := Data{}
|
||||||
|
bts, _ := v.MarshalMsg(nil)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodeData(t *testing.T) {
|
||||||
|
v := Data{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecodeData Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := Data{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodeData(b *testing.B) {
|
||||||
|
v := Data{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeData(b *testing.B) {
|
||||||
|
v := Data{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalUnmarshalStatusBody(t *testing.T) {
|
||||||
|
v := StatusBody{}
|
||||||
|
bts, err := v.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
left, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
|
||||||
|
left, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(left) > 0 {
|
||||||
|
t.Errorf("%d bytes left over after Skip(): %q", len(left), left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMarshalMsgStatusBody(b *testing.B) {
|
||||||
|
v := StatusBody{}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.MarshalMsg(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAppendMsgStatusBody(b *testing.B) {
|
||||||
|
v := StatusBody{}
|
||||||
|
bts := make([]byte, 0, v.Msgsize())
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bts, _ = v.MarshalMsg(bts[0:0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshalStatusBody(b *testing.B) {
|
||||||
|
v := StatusBody{}
|
||||||
|
bts, _ := v.MarshalMsg(nil)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.SetBytes(int64(len(bts)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := v.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeDecodeStatusBody(t *testing.T) {
|
||||||
|
v := StatusBody{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
|
||||||
|
m := v.Msgsize()
|
||||||
|
if buf.Len() > m {
|
||||||
|
t.Log("WARNING: TestEncodeDecodeStatusBody Msgsize() is inaccurate")
|
||||||
|
}
|
||||||
|
|
||||||
|
vn := StatusBody{}
|
||||||
|
err := msgp.Decode(&buf, &vn)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Reset()
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
err = msgp.NewReader(&buf).Skip()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEncodeStatusBody(b *testing.B) {
|
||||||
|
v := StatusBody{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
en := msgp.NewWriter(msgp.Nowhere)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
v.EncodeMsg(en)
|
||||||
|
}
|
||||||
|
en.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeStatusBody(b *testing.B) {
|
||||||
|
v := StatusBody{}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
msgp.Encode(&buf, &v)
|
||||||
|
b.SetBytes(int64(buf.Len()))
|
||||||
|
rd := msgp.NewEndlessReader(buf.Bytes(), b)
|
||||||
|
dc := msgp.NewReader(rd)
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := v.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/kschamplin/gotelem/can"
|
"github.com/kschamplin/gotelem/internal/can"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kschamplin/gotelem/can"
|
"github.com/kschamplin/gotelem/internal/can"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
235
internal/xbee/api_frame.go
Normal file
235
internal/xbee/api_frame.go
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
package xbee
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// the frames have an outer shell - we will make a function that takes
|
||||||
|
// an inner frame element and wraps it in the appropriate headers.
|
||||||
|
|
||||||
|
// first, we should make it take the frame directly, so we make an interface
|
||||||
|
// that represents "framable" things. note that bytes.Buffer also fulfils this.
|
||||||
|
|
||||||
|
type Frameable interface {
|
||||||
|
// returns the API identifier for this frame.
|
||||||
|
GetId() byte
|
||||||
|
// encodes this frame correctly.
|
||||||
|
Bytes() ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we can describe our function that takes a framable and contains it + calculates checksums.
|
||||||
|
func calculateChecksum(data []byte) byte {
|
||||||
|
var sum byte
|
||||||
|
for _, v := range data {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
return 0xFF - sum
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteFrame(w io.Writer, cmd Frameable) (n int, err error) {
|
||||||
|
frame_data, err := cmd.Bytes()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
frame := make([]byte, len(frame_data)+4)
|
||||||
|
frame[0] = 0x7E
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint16(frame[1:], uint16(len(frame_data)))
|
||||||
|
|
||||||
|
copy(frame[3:], frame_data)
|
||||||
|
|
||||||
|
chk := calculateChecksum(frame_data)
|
||||||
|
|
||||||
|
frame[len(frame)-1] = chk
|
||||||
|
return w.Write(frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeXbeeApiFrame(cmd Frameable) ([]byte, error) {
|
||||||
|
dataBuf, _ := cmd.Bytes()
|
||||||
|
frameBuf := make([]byte, len(dataBuf)+4)
|
||||||
|
|
||||||
|
// move data and construct the frame
|
||||||
|
|
||||||
|
frameBuf[0] = 0x7E // start delimiter
|
||||||
|
|
||||||
|
// length
|
||||||
|
// todo: check endiannes (0x7e, msb lsb)
|
||||||
|
binary.BigEndian.PutUint16(frameBuf[1:3], uint16(len(dataBuf)))
|
||||||
|
|
||||||
|
copy(frameBuf[3:], dataBuf)
|
||||||
|
|
||||||
|
chksum := calculateChecksum(dataBuf)
|
||||||
|
|
||||||
|
frameBuf[len(frameBuf)-1] = chksum
|
||||||
|
|
||||||
|
return frameBuf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we can describe frames in other files that implement Frameable.
|
||||||
|
// the remaining challenge is reception and actual API frames.
|
||||||
|
// xbee uses the first byte of the "frame data" as the API identifier or command.
|
||||||
|
|
||||||
|
//go:generate stringer -output=api_frame_cmd.go -type xbeeCmd
|
||||||
|
type XBeeCmd byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
// commands sent to the xbee s3b
|
||||||
|
|
||||||
|
ATCmd XBeeCmd = 0x08 // AT Command
|
||||||
|
ATCmdQueue XBeeCmd = 0x09 // AT Command - Queue Parameter Value
|
||||||
|
TxReq XBeeCmd = 0x10 // TX Request
|
||||||
|
TxReqExpl XBeeCmd = 0x11 // Explicit TX Request
|
||||||
|
RemoteCmdReq XBeeCmd = 0x17 // Remote Command Request
|
||||||
|
// commands recieved from the xbee
|
||||||
|
|
||||||
|
ATCmdResponse XBeeCmd = 0x88 // AT Command Response
|
||||||
|
ModemStatus XBeeCmd = 0x8A // Modem Status
|
||||||
|
TxStatus XBeeCmd = 0x8B // Transmit Status
|
||||||
|
RouteInfoPkt XBeeCmd = 0x8D // Route information packet
|
||||||
|
AddrUpdate XBeeCmd = 0x8E // Aggregate Addressing Update
|
||||||
|
RxPkt XBeeCmd = 0x90 // RX Indicator (AO=0)
|
||||||
|
RxPktExpl XBeeCmd = 0x91 // Explicit RX Indicator (AO=1)
|
||||||
|
IOSample XBeeCmd = 0x92 // Data Sample RX Indicator
|
||||||
|
NodeId XBeeCmd = 0x95 // Note Identification Indicator
|
||||||
|
RemoteCmdResp XBeeCmd = 0x97 // Remote Command Response
|
||||||
|
)
|
||||||
|
|
||||||
|
// AT commands are hard, so let's write out all the major ones here
|
||||||
|
|
||||||
|
type ATCmdFrame struct {
|
||||||
|
Id byte
|
||||||
|
Cmd string
|
||||||
|
Param []byte
|
||||||
|
Queued bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// implement the frame stuff for us.
|
||||||
|
func (atFrame *ATCmdFrame) Bytes() ([]byte, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
if atFrame.Queued {
|
||||||
|
// queued (batched) at comamnds have different Frame type
|
||||||
|
buf.WriteByte(byte(ATCmdQueue))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// normal frame type
|
||||||
|
buf.WriteByte(byte(ATCmd))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteByte(atFrame.Id)
|
||||||
|
|
||||||
|
// write cmd, if it's the right length.
|
||||||
|
if cmdLen := len(atFrame.Cmd); cmdLen != 2 {
|
||||||
|
return nil, fmt.Errorf("AT command incorrect length: %d", cmdLen)
|
||||||
|
}
|
||||||
|
buf.Write([]byte(atFrame.Cmd))
|
||||||
|
|
||||||
|
// write param.
|
||||||
|
buf.Write(atFrame.Param)
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// transmissions to this address are instead broadcast
|
||||||
|
const BroadcastAddr = 0xFFFF
|
||||||
|
|
||||||
|
type TxFrame struct {
|
||||||
|
Id byte
|
||||||
|
Destination uint64
|
||||||
|
BCastRadius uint8
|
||||||
|
Options uint8
|
||||||
|
Payload []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (txFrame *TxFrame) Bytes() ([]byte, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
buf.WriteByte(byte(TxReq))
|
||||||
|
|
||||||
|
buf.WriteByte(txFrame.Id)
|
||||||
|
|
||||||
|
a := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(a, txFrame.Destination)
|
||||||
|
buf.Write(a)
|
||||||
|
|
||||||
|
// write the reserved part.
|
||||||
|
buf.Write([]byte{0xFF, 0xFE})
|
||||||
|
|
||||||
|
// write the radius
|
||||||
|
buf.WriteByte(txFrame.BCastRadius)
|
||||||
|
|
||||||
|
buf.WriteByte(txFrame.Options)
|
||||||
|
|
||||||
|
buf.Write(txFrame.Payload)
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type RemoteATCmdReq struct {
|
||||||
|
ATCmdFrame
|
||||||
|
Destination uint64
|
||||||
|
Options uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (remoteAT *RemoteATCmdReq) Bytes() ([]byte, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
buf.WriteByte(byte(RemoteCmdReq))
|
||||||
|
|
||||||
|
buf.WriteByte(remoteAT.Id)
|
||||||
|
|
||||||
|
a := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(a, remoteAT.Destination)
|
||||||
|
buf.Write(a)
|
||||||
|
|
||||||
|
// write the reserved part.
|
||||||
|
buf.Write([]byte{0xFF, 0xFE})
|
||||||
|
// write options
|
||||||
|
buf.WriteByte(remoteAT.Options)
|
||||||
|
|
||||||
|
// now, write the AT command and the data.
|
||||||
|
buf.Write([]byte(remoteAT.Cmd))
|
||||||
|
|
||||||
|
buf.Write(remoteAT.Param)
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we will implement receiving packets from a character stream.
|
||||||
|
// we first need to make a thing that produces frames from a stream using a scanner.
|
||||||
|
|
||||||
|
// this is a split function for bufio.scanner. It makes it easier to handle the FSM
|
||||||
|
// for extracting data from a stream. For the Xbee, this means that we must
|
||||||
|
// find the magic start character, (check that it's escaped), read the length,
|
||||||
|
// and then ensure we have enough length to finish the token, requesting more data
|
||||||
|
// if we do not.
|
||||||
|
//
|
||||||
|
// see https://pkg.go.dev/bufio#SplitFunc for more info
|
||||||
|
// https://medium.com/golangspec/in-depth-introduction-to-bufio-scanner-in-golang-55483bb689b4
|
||||||
|
func xbeeFrameSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
if atEOF && len(data) == 0 {
|
||||||
|
// there's no data, request more.
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if startIdx := bytes.IndexByte(data, 0x7E); startIdx >= 0 {
|
||||||
|
// we have a start character. get the length.
|
||||||
|
// we add 4 since start delimiter (1) + length (2) + checksum (1).
|
||||||
|
// the length inside the packet represents the frame data only.
|
||||||
|
var frameLen = binary.BigEndian.Uint16(data[startIdx+1:startIdx+3]) + 4
|
||||||
|
if len(data[startIdx:]) < int(frameLen) {
|
||||||
|
// we got the length, but there's not enough data for the frame. we can trim the
|
||||||
|
// data that came before the start, but not return a token.
|
||||||
|
return startIdx, nil, nil
|
||||||
|
}
|
||||||
|
// there is enough data to pull a frame.
|
||||||
|
// todo: check checksum here? we can return an error.
|
||||||
|
return startIdx + int(frameLen), data[startIdx : startIdx+int(frameLen)], nil
|
||||||
|
}
|
||||||
|
// we didn't find a start character in our data, so request more. trash everythign given to us
|
||||||
|
return len(data), nil, nil
|
||||||
|
}
|
119
internal/xbee/api_frame_test.go
Normal file
119
internal/xbee/api_frame_test.go
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
package xbee
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_xbeeFrameSplit(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
data []byte
|
||||||
|
atEOF bool
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantAdvance int
|
||||||
|
wantToken []byte
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
{
|
||||||
|
name: "empty data",
|
||||||
|
args: args{
|
||||||
|
data: []byte{},
|
||||||
|
atEOF: false,
|
||||||
|
},
|
||||||
|
wantAdvance: 0,
|
||||||
|
wantToken: nil,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no start delimiter",
|
||||||
|
args: args{
|
||||||
|
data: []byte{0x11, 0x22, 0x23, 0x44, 0x44, 0x77, 0x33},
|
||||||
|
atEOF: false,
|
||||||
|
},
|
||||||
|
wantAdvance: 7,
|
||||||
|
wantToken: nil,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "incomplete packet",
|
||||||
|
args: args{
|
||||||
|
data: []byte{0x7E, 0x00, 0x02, 0x23, 0x11},
|
||||||
|
atEOF: false,
|
||||||
|
},
|
||||||
|
wantAdvance: 0,
|
||||||
|
wantToken: nil,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid packet",
|
||||||
|
args: args{
|
||||||
|
data: []byte{0x7E, 0x00, 0x02, 0x23, 0x11, 0xCB},
|
||||||
|
atEOF: false,
|
||||||
|
},
|
||||||
|
wantAdvance: 6,
|
||||||
|
wantToken: []byte{0x7E, 0x00, 0x02, 0x23, 0x11, 0xCB},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid packet w/ padding",
|
||||||
|
args: args{
|
||||||
|
data: []byte{0x00, 0x7E, 0x00, 0x02, 0x23, 0x11, 0xCB, 0x00},
|
||||||
|
atEOF: false,
|
||||||
|
},
|
||||||
|
wantAdvance: 7,
|
||||||
|
wantToken: []byte{0x7E, 0x00, 0x02, 0x23, 0x11, 0xCB},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotAdvance, gotToken, err := xbeeFrameSplit(tt.args.data, tt.args.atEOF)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("xbeeFrameSplit() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gotAdvance != tt.wantAdvance {
|
||||||
|
t.Errorf("xbeeFrameSplit() gotAdvance = %v, want %v", gotAdvance, tt.wantAdvance)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotToken, tt.wantToken) {
|
||||||
|
t.Errorf("xbeeFrameSplit() gotToken = %v, want %v", gotToken, tt.wantToken)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteFrame(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
cmd Frameable
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantN int
|
||||||
|
wantW string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
w := &bytes.Buffer{}
|
||||||
|
gotN, err := WriteFrame(w, tt.args.cmd)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("WriteFrame() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gotN != tt.wantN {
|
||||||
|
t.Errorf("WriteFrame() = %v, want %v", gotN, tt.wantN)
|
||||||
|
}
|
||||||
|
if gotW := w.String(); gotW != tt.wantW {
|
||||||
|
t.Errorf("WriteFrame() = %v, want %v", gotW, tt.wantW)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,71 +0,0 @@
|
||||||
package xbee
|
|
||||||
|
|
||||||
import "encoding/binary"
|
|
||||||
|
|
||||||
// the frames have an outer shell - we will make a function that takes
|
|
||||||
// an inner frame element and wraps it in the appropriate headers.
|
|
||||||
|
|
||||||
// first, we should make it take the frame directly, so we make an interface
|
|
||||||
// that represents "framable" things. note that bytes.Buffer also fulfils this.
|
|
||||||
|
|
||||||
type Frameable interface {
|
|
||||||
Bytes() []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we can describe our function that takes a framable and contains it + calculates checksums.
|
|
||||||
func calculateChecksum(data []byte) byte {
|
|
||||||
var sum byte
|
|
||||||
for _, v := range data {
|
|
||||||
sum += v
|
|
||||||
}
|
|
||||||
return 0xFF - sum
|
|
||||||
}
|
|
||||||
func makeXbeeApiFrame(cmd Frameable) ([]byte, error) {
|
|
||||||
dataBuf := cmd.Bytes()
|
|
||||||
frameBuf := make([]byte, len(dataBuf)+4)
|
|
||||||
|
|
||||||
// move data and construct the frame
|
|
||||||
|
|
||||||
frameBuf[0] = 0x7E // start delimiter
|
|
||||||
|
|
||||||
// length
|
|
||||||
// todo: check endiannes (0x7e, msb lsb)
|
|
||||||
binary.LittleEndian.PutUint16(frameBuf[1:3], uint16(len(dataBuf)))
|
|
||||||
|
|
||||||
copy(frameBuf[3:], dataBuf)
|
|
||||||
|
|
||||||
chksum := calculateChecksum(dataBuf)
|
|
||||||
|
|
||||||
frameBuf[len(frameBuf)-1] = chksum
|
|
||||||
|
|
||||||
return frameBuf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we can describe frames in other files that implement Frameable. this makes trasmission complete.
|
|
||||||
// the remaining challenge is reception and actual API frames.
|
|
||||||
// xbee uses the first byte of the "frame data" as the API identifier or command.
|
|
||||||
|
|
||||||
//go:generate stringer -output=api_frame_cmd.go -type xbeeCmd
|
|
||||||
type xbeeCmd byte
|
|
||||||
|
|
||||||
const (
|
|
||||||
// commands sent to the xbee s3b
|
|
||||||
|
|
||||||
ATCmd xbeeCmd = 0x08 // AT Command
|
|
||||||
ATCmdQueuePVal xbeeCmd = 0x09 // AT Command - Queue Parameter Value
|
|
||||||
TxReq xbeeCmd = 0x10 // TX Request
|
|
||||||
TxReqExpl xbeeCmd = 0x11 // Explicit TX Request
|
|
||||||
RemoteCmdReq xbeeCmd = 0x17 // Remote Command Request
|
|
||||||
// commands recieved from the xbee
|
|
||||||
|
|
||||||
ATCmdResponse xbeeCmd = 0x88 // AT Command Response
|
|
||||||
ModemStatus xbeeCmd = 0x8A // Modem Status
|
|
||||||
TxStatus xbeeCmd = 0x8B // Transmit Status
|
|
||||||
RouteInfoPkt xbeeCmd = 0x8D // Route information packet
|
|
||||||
AddrUpdate xbeeCmd = 0x8E // Aggregate Addressing Update
|
|
||||||
RxPkt xbeeCmd = 0x90 // RX Indicator (AO=0)
|
|
||||||
RxPktExpl xbeeCmd = 0x91 // Explicit RX Indicator (AO=1)
|
|
||||||
IOSample xbeeCmd = 0x92 // Data Sample RX Indicator
|
|
||||||
NodeId xbeeCmd = 0x95 // Note Identification Indicator
|
|
||||||
RemoteCmdResp xbeeCmd = 0x97 // Remote Command Response
|
|
||||||
)
|
|
|
@ -1 +0,0 @@
|
||||||
package xbee_test
|
|
Loading…
Reference in a new issue