skylab: rework interface
This commit is contained in:
parent
96149ee38b
commit
2dceb3927e
93
broker.go
93
broker.go
|
@ -2,104 +2,29 @@ package gotelem
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/kschamplin/gotelem/skylab"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
type BrokerRequest struct {
|
||||
Source string // the name of the sender
|
||||
Msg Frame // the message to send
|
||||
}
|
||||
type BrokerClient struct {
|
||||
Name string // the name of the client
|
||||
Ch chan Frame // the channel to send frames to this client
|
||||
}
|
||||
type Broker struct {
|
||||
subs map[string]chan Frame
|
||||
|
||||
publishCh chan BrokerRequest
|
||||
|
||||
subsCh chan BrokerClient
|
||||
unsubCh chan BrokerClient
|
||||
}
|
||||
|
||||
|
||||
// Start runs the broker and sends messages to the subscribers (but not the sender)
|
||||
func (b *Broker) Start() {
|
||||
|
||||
for {
|
||||
select {
|
||||
case newClient := <-b.subsCh:
|
||||
b.subs[newClient.Name] = newClient.Ch
|
||||
case req := <-b.publishCh:
|
||||
for name, ch := range b.subs {
|
||||
if name == req.Source {
|
||||
continue // don't send to ourselves.
|
||||
}
|
||||
// a kinda-inelegant non-blocking push.
|
||||
// if we can't do it, we just drop it. this should ideally never happen.
|
||||
select {
|
||||
case ch <- req.Msg:
|
||||
default:
|
||||
fmt.Printf("we dropped a packet to dest %s", name)
|
||||
}
|
||||
}
|
||||
case clientToRemove := <-b.unsubCh:
|
||||
close(b.subs[clientToRemove.Name])
|
||||
delete(b.subs, clientToRemove.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Broker) Publish(name string, msg Frame) {
|
||||
breq := BrokerRequest{
|
||||
Source: name,
|
||||
Msg: msg,
|
||||
}
|
||||
b.publishCh <- breq
|
||||
}
|
||||
|
||||
func (b *Broker) Subscribe(name string) <-chan Frame {
|
||||
ch := make(chan Frame, 3)
|
||||
|
||||
bc := BrokerClient{
|
||||
Name: name,
|
||||
Ch: ch,
|
||||
}
|
||||
b.subsCh <- bc
|
||||
return ch
|
||||
}
|
||||
|
||||
func (b *Broker) Unsubscribe(name string) {
|
||||
bc := BrokerClient{
|
||||
Name: name,
|
||||
}
|
||||
b.unsubCh <- bc
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
type JBroker struct {
|
||||
subs map[string] chan CANDumpEntry // contains the channel for each subsciber
|
||||
subs map[string]chan skylab.BusEvent // contains the channel for each subsciber
|
||||
|
||||
logger *slog.Logger
|
||||
lock sync.RWMutex
|
||||
logger *slog.Logger
|
||||
lock sync.RWMutex
|
||||
bufsize int // size of chan buffer in elements.
|
||||
}
|
||||
|
||||
|
||||
func NewBroker(bufsize int, logger *slog.Logger) *JBroker {
|
||||
return &JBroker{
|
||||
subs: make(map[string]chan CANDumpEntry),
|
||||
logger: logger,
|
||||
subs: make(map[string]chan skylab.BusEvent),
|
||||
logger: logger,
|
||||
bufsize: bufsize,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *JBroker) Subscribe(name string) (ch chan CANDumpEntry, err error) {
|
||||
func (b *JBroker) Subscribe(name string) (ch chan skylab.BusEvent, err error) {
|
||||
// get rw lock.
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
@ -108,7 +33,7 @@ func (b *JBroker) Subscribe(name string) (ch chan CANDumpEntry, err error) {
|
|||
return nil, errors.New("name already in use")
|
||||
}
|
||||
b.logger.Info("new subscriber", "name", name)
|
||||
ch = make(chan CANDumpEntry, b.bufsize)
|
||||
ch = make(chan skylab.BusEvent, b.bufsize)
|
||||
|
||||
b.subs[name] = ch
|
||||
return
|
||||
|
@ -121,7 +46,7 @@ func (b *JBroker) Unsubscribe(name string) {
|
|||
delete(b.subs, name)
|
||||
}
|
||||
|
||||
func (b *JBroker) Publish(sender string, message CANDumpEntry) {
|
||||
func (b *JBroker) Publish(sender string, message skylab.BusEvent) {
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
for name, ch := range b.subs {
|
||||
|
|
|
@ -3,28 +3,26 @@ package cli
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
imgui "github.com/AllenDang/cimgui-go"
|
||||
"github.com/kschamplin/gotelem"
|
||||
"github.com/kschamplin/gotelem/mprpc"
|
||||
"github.com/urfave/cli/v2"
|
||||
imgui "github.com/AllenDang/cimgui-go"
|
||||
)
|
||||
|
||||
|
||||
func init() {
|
||||
subCmds = append(subCmds, clientCmd)
|
||||
}
|
||||
|
||||
|
||||
var clientCmd = &cli.Command{
|
||||
Name: "client",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "interact with a gotelem server",
|
||||
Name: "client",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "interact with a gotelem server",
|
||||
ArgsUsage: "[server url]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "gui",
|
||||
Name: "gui",
|
||||
Aliases: []string{"g"},
|
||||
Usage: "start a local TUI",
|
||||
Usage: "start a local TUI",
|
||||
},
|
||||
},
|
||||
Description: `
|
||||
|
@ -33,7 +31,6 @@ Connects to a gotelem server or relay. Can be used to
|
|||
Action: client,
|
||||
}
|
||||
|
||||
|
||||
func loop() {
|
||||
imgui.ShowDemoWindow()
|
||||
}
|
||||
|
@ -45,13 +42,8 @@ func client(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
|
||||
// the client should connect to a TCP server and listen to packets.
|
||||
func CANFrameHandler(f *gotelem.Frame) (*mprpc.RPCEmpty, error){
|
||||
func CANFrameHandler(f *gotelem.Frame) (*mprpc.RPCEmpty, error) {
|
||||
fmt.Printf("got frame, %v\n", f)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var initialRPCHandlers = map[string]mprpc.ServiceFunc{
|
||||
"can": mprpc.MakeService(CANFrameHandler),
|
||||
}
|
||||
|
|
|
@ -37,11 +37,9 @@ var serveCmd = &cli.Command{
|
|||
Action: serve,
|
||||
}
|
||||
|
||||
|
||||
// FIXME: naming
|
||||
// this is a server handler for i.e tcp socket, http server, socketCAN, xbee,
|
||||
// etc. we can register them in init() functions.
|
||||
type testThing func(cCtx *cli.Context, broker *gotelem.Broker, logger *slog.Logger) (err error)
|
||||
|
||||
type service interface {
|
||||
fmt.Stringer
|
||||
|
@ -58,12 +56,6 @@ var serveThings = []service{
|
|||
&rpcService{},
|
||||
}
|
||||
|
||||
|
||||
func deriveLogger (oldLogger *slog.Logger, svc service) (newLogger *slog.Logger) {
|
||||
newLogger = oldLogger.With("svc", svc.String())
|
||||
return
|
||||
}
|
||||
|
||||
func serve(cCtx *cli.Context) error {
|
||||
// TODO: output both to stderr and a file.
|
||||
logger := slog.New(slog.NewTextHandler(os.Stderr))
|
||||
|
@ -85,14 +77,11 @@ func serve(cCtx *cli.Context) error {
|
|||
}(svc, logger)
|
||||
}
|
||||
|
||||
|
||||
wg.Wait()
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
type rpcService struct {
|
||||
}
|
||||
|
||||
|
@ -162,8 +151,7 @@ func (c *CanLoggerService) String() string {
|
|||
func (c *CanLoggerService) Status() {
|
||||
}
|
||||
|
||||
|
||||
func (c *CanLoggerService) Start(cCtx *cli.Context, broker *gotelem.JBroker, l *slog.Logger) (err error) {
|
||||
func (c *CanLoggerService) Start(cCtx *cli.Context, broker *gotelem.JBroker, l *slog.Logger) (err error) {
|
||||
rxCh, err := broker.Subscribe("canDump")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -194,7 +182,6 @@ func (c *CanLoggerService) Start(cCtx *cli.Context, broker *gotelem.JBroker, l
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// XBeeService provides data over an Xbee device, either by serial or TCP
|
||||
// based on the url provided in the xbee flag. see the description for details.
|
||||
type XBeeService struct {
|
||||
|
@ -207,7 +194,6 @@ func (x *XBeeService) String() string {
|
|||
func (x *XBeeService) Status() {
|
||||
}
|
||||
|
||||
|
||||
func (x *XBeeService) Start(cCtx *cli.Context, broker *gotelem.JBroker, logger *slog.Logger) (err error) {
|
||||
if cCtx.String("xbee") == "" {
|
||||
logger.Info("not using xbee")
|
||||
|
@ -245,7 +231,5 @@ func (x *XBeeService) Start(cCtx *cli.Context, broker *gotelem.JBroker, logger *
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@ import (
|
|||
// It is an example of the modular architecture of the command line and server stack.
|
||||
|
||||
var canDevFlag = &cli.StringFlag{
|
||||
Name: "can",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "CAN device string",
|
||||
EnvVars: []string{"CAN_DEVICE"},
|
||||
Name: "can",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "CAN device string",
|
||||
EnvVars: []string{"CAN_DEVICE"},
|
||||
}
|
||||
|
||||
// this function sets up the `serve` flags and services that use socketCAN
|
||||
|
@ -37,10 +37,9 @@ func init() {
|
|||
subCmds = append(subCmds, socketCANCmd)
|
||||
}
|
||||
|
||||
|
||||
type socketCANService struct {
|
||||
name string
|
||||
sock socketcan.CanSocket
|
||||
sock *socketcan.CanSocket
|
||||
}
|
||||
|
||||
func (s *socketCANService) Status() {
|
||||
|
@ -66,13 +65,13 @@ func (s *socketCANService) Start(cCtx *cli.Context, broker *gotelem.JBroker, log
|
|||
go vcanTest(cCtx.String("can"))
|
||||
}
|
||||
|
||||
sock, err := socketcan.NewCanSocket(cCtx.String("can"))
|
||||
s.sock, err = socketcan.NewCanSocket(cCtx.String("can"))
|
||||
if err != nil {
|
||||
logger.Error("error opening socket", "err", err)
|
||||
return
|
||||
}
|
||||
defer sock.Close()
|
||||
s.name = sock.Name()
|
||||
defer s.sock.Close()
|
||||
s.name = s.sock.Name()
|
||||
|
||||
// connect to the broker
|
||||
rxCh, err := broker.Subscribe("socketCAN")
|
||||
|
@ -81,13 +80,12 @@ func (s *socketCANService) Start(cCtx *cli.Context, broker *gotelem.JBroker, log
|
|||
}
|
||||
defer broker.Unsubscribe("socketCAN")
|
||||
|
||||
|
||||
// make a channel to receive socketCAN frames.
|
||||
rxCan := make(chan gotelem.Frame)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
pkt, err := sock.Recv()
|
||||
pkt, err := s.sock.Recv()
|
||||
if err != nil {
|
||||
logger.Warn("error receiving CAN packet", "err", err)
|
||||
}
|
||||
|
@ -100,12 +98,12 @@ func (s *socketCANService) Start(cCtx *cli.Context, broker *gotelem.JBroker, log
|
|||
select {
|
||||
case msg := <-rxCh:
|
||||
|
||||
id, d, _ := skylab.CanSend(msg.Data)
|
||||
id, d, _ := skylab.ToCanFrame(msg.Data)
|
||||
|
||||
frame.Id = id
|
||||
frame.Data = d
|
||||
|
||||
sock.Send(&frame)
|
||||
s.sock.Send(&frame)
|
||||
|
||||
case msg := <-rxCan:
|
||||
p, err := skylab.FromCanFrame(msg.Id, msg.Data)
|
||||
|
@ -113,10 +111,10 @@ func (s *socketCANService) Start(cCtx *cli.Context, broker *gotelem.JBroker, log
|
|||
logger.Warn("error parsing can packet", "id", msg.Id)
|
||||
continue
|
||||
}
|
||||
cde := gotelem.CANDumpEntry{
|
||||
cde := skylab.BusEvent{
|
||||
Timestamp: float64(time.Now().UnixNano()) / 1e9,
|
||||
Id: uint64(msg.Id),
|
||||
Data: p,
|
||||
Id: uint64(msg.Id),
|
||||
Data: p,
|
||||
}
|
||||
broker.Publish("socketCAN", cde)
|
||||
case <-cCtx.Done():
|
||||
|
@ -161,14 +159,13 @@ func vcanTest(devname string) {
|
|||
Id: 0.2,
|
||||
}
|
||||
|
||||
id, data, err := skylab.CanSend(&testPkt)
|
||||
id, data, err := skylab.ToCanFrame(&testPkt)
|
||||
testFrame := gotelem.Frame{
|
||||
Id: id,
|
||||
Id: id,
|
||||
Data: data,
|
||||
Kind: gotelem.CanSFFFrame,
|
||||
}
|
||||
|
||||
|
||||
for {
|
||||
slog.Info("sending test packet")
|
||||
sock.Send(&testFrame)
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/kschamplin/gotelem"
|
||||
"github.com/kschamplin/gotelem/skylab"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
@ -92,7 +91,7 @@ func run(ctx *cli.Context) (err error) {
|
|||
|
||||
segments := strings.Split(dumpLine, " ")
|
||||
|
||||
var cd gotelem.CANDumpEntry
|
||||
var cd skylab.BusEvent
|
||||
// this is cursed but easiest way to get a float from a string.
|
||||
fmt.Sscanf(segments[0], "(%g)", &cd.Timestamp)
|
||||
|
||||
|
|
3
frame.go
3
frame.go
|
@ -6,7 +6,6 @@
|
|||
// by writing "adapters" to various devices/formats (xbee, sqlite, network socket, socketcan)
|
||||
package gotelem
|
||||
|
||||
|
||||
// Frame represents a protocol-agnostic CAN frame. The Id can be standard or extended,
|
||||
// but if it is extended, the Kind should be EFF.
|
||||
type Frame struct {
|
||||
|
@ -15,7 +14,6 @@ type Frame struct {
|
|||
Kind Kind
|
||||
}
|
||||
|
||||
//go:generate msgp
|
||||
type CANFrame interface {
|
||||
Id() uint32
|
||||
Data() []byte
|
||||
|
@ -58,4 +56,3 @@ type CanTransciever interface {
|
|||
CanSink
|
||||
CanSource
|
||||
}
|
||||
|
||||
|
|
1
go.mod
1
go.mod
|
@ -20,4 +20,5 @@ require (
|
|||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/stretchr/testify v1.8.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
@ -18,14 +18,13 @@ import (
|
|||
// SkylabFile is a yaml file from skylab.
|
||||
type SkylabFile struct {
|
||||
Packets []PacketDef
|
||||
Boards []BoardSpec
|
||||
|
||||
Boards []BoardSpec
|
||||
}
|
||||
|
||||
type BoardSpec struct {
|
||||
Name string
|
||||
Name string
|
||||
Transmit []string
|
||||
Recieve []string
|
||||
Recieve []string
|
||||
}
|
||||
|
||||
// data field.
|
||||
|
@ -80,6 +79,10 @@ var typeSizeMap = map[string]uint{
|
|||
"bitfield": 1,
|
||||
}
|
||||
|
||||
func MapType(ctype string) string {
|
||||
return typeMap[ctype]
|
||||
}
|
||||
|
||||
func (d *DataField) ToStructMember(parentName string) string {
|
||||
|
||||
if d.Type == "bitfield" {
|
||||
|
@ -96,12 +99,12 @@ func (d *DataField) MakeMarshal(offset int) string {
|
|||
if d.Type == "uint8_t" || d.Type == "int8_t" {
|
||||
return fmt.Sprintf("b[%d] = p.%s", offset, fieldName)
|
||||
} else if d.Type == "bitfield" {
|
||||
return fmt.Sprintf("b[%d] = p.%s.Marshal()", offset,fieldName)
|
||||
return fmt.Sprintf("b[%d] = p.%s.MarshalByte()", offset, fieldName)
|
||||
} else if d.Type == "float" {
|
||||
|
||||
return fmt.Sprintf("float32ToBytes(b[%d:], p.%s, false)", offset, fieldName)
|
||||
|
||||
} else if t ,ok := typeMap[d.Type]; ok {
|
||||
} else if t, ok := typeMap[d.Type]; ok {
|
||||
// it's uint or int of some kind, use endian to write it.
|
||||
if strings.HasPrefix(t, "i") {
|
||||
// this means it's a signed integer.
|
||||
|
@ -114,14 +117,13 @@ func (d *DataField) MakeMarshal(offset int) string {
|
|||
return "panic(\"failed to do it\")\n"
|
||||
}
|
||||
|
||||
|
||||
func (d *DataField) MakeUnmarshal(offset int) string {
|
||||
|
||||
fieldName := toCamelInitCase(d.Name, true)
|
||||
if d.Type == "uint8_t" || d.Type == "int8_t" {
|
||||
return fmt.Sprintf("p.%s = b[%d]", fieldName, offset)
|
||||
} else if d.Type == "bitfield" {
|
||||
return fmt.Sprintf("p.%s.Unmarshal(b[%d])", fieldName, offset)
|
||||
return fmt.Sprintf("p.%s.UnmarshalByte(b[%d])", fieldName, offset)
|
||||
} else if d.Type == "float" {
|
||||
|
||||
return fmt.Sprintf("p.%s = float32FromBytes(b[%d:], false)", fieldName, offset)
|
||||
|
@ -140,8 +142,6 @@ func (d *DataField) MakeUnmarshal(offset int) string {
|
|||
panic("unhandled type")
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (p PacketDef) CalcSize() int {
|
||||
// makes a function that returns the size of the code.
|
||||
|
||||
|
@ -153,7 +153,6 @@ func (p PacketDef) CalcSize() int {
|
|||
return size
|
||||
}
|
||||
|
||||
|
||||
func (p PacketDef) MakeMarshal() string {
|
||||
var buf strings.Builder
|
||||
|
||||
|
@ -170,14 +169,12 @@ func (p PacketDef) MakeMarshal() string {
|
|||
offset += int(typeSizeMap[val.Type])
|
||||
}
|
||||
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (p PacketDef) MakeUnmarshal() string {
|
||||
var buf strings.Builder
|
||||
|
||||
|
||||
var offset int = 0
|
||||
for _, val := range p.Data {
|
||||
|
||||
|
@ -190,7 +187,6 @@ func (p PacketDef) MakeUnmarshal() string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
|
||||
// stolen camelCaser code. initCase = true means CamelCase, false means camelCase
|
||||
func toCamelInitCase(s string, initCase bool) string {
|
||||
s = strings.TrimSpace(s)
|
||||
|
@ -231,24 +227,23 @@ func toCamelInitCase(s string, initCase bool) string {
|
|||
// N takes a start and stop value and returns a stream of
|
||||
// [start, end), including the starting value but excluding the end value.
|
||||
func N(start, end int) (stream chan int) {
|
||||
stream = make(chan int)
|
||||
go func() {
|
||||
for i := start; i < end; i++ {
|
||||
stream <- i
|
||||
}
|
||||
close(stream)
|
||||
}()
|
||||
return
|
||||
stream = make(chan int)
|
||||
go func() {
|
||||
for i := start; i < end; i++ {
|
||||
stream <- i
|
||||
}
|
||||
close(stream)
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Nx takes a start, a quantity, and an offset and returns a stream
|
||||
// of `times` values which count from start and increment by `offset` each
|
||||
// time.
|
||||
func Nx (start, times, offset int) (elems []int) {
|
||||
func Nx(start, times, offset int) (elems []int) {
|
||||
elems = make([]int, times)
|
||||
for i := 0; i < times; i++ {
|
||||
elems[i] = start + offset * i
|
||||
elems[i] = start + offset*i
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -259,10 +254,10 @@ func uint32ToInt(i uint32) (o int) {
|
|||
return int(i)
|
||||
}
|
||||
|
||||
|
||||
// strJoin is a remapping of strings.Join so that we can use
|
||||
// it in a pipeline.
|
||||
// {{.Names | strJoin ", " }}
|
||||
//
|
||||
// {{.Names | strJoin ", " }}
|
||||
func strJoin(delim string, elems []string) string {
|
||||
return strings.Join(elems, delim)
|
||||
}
|
||||
|
@ -277,7 +272,6 @@ func mapf(format string, els []int) []string {
|
|||
return resp
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
// read path as the first arg, glob it for yamls, read each yaml into a skylabFile.
|
||||
// then take each skylab file, put all the packets into one big array.
|
||||
|
@ -315,12 +309,13 @@ func main() {
|
|||
// we add any functions mapping we need here.
|
||||
fnMap := template.FuncMap{
|
||||
"camelCase": toCamelInitCase,
|
||||
"Time": time.Now,
|
||||
"N": N,
|
||||
"Nx": Nx,
|
||||
"int": uint32ToInt,
|
||||
"strJoin": strJoin,
|
||||
"mapf": mapf,
|
||||
"Time": time.Now,
|
||||
"N": N,
|
||||
"Nx": Nx,
|
||||
"int": uint32ToInt,
|
||||
"strJoin": strJoin,
|
||||
"mapf": mapf,
|
||||
"maptype": MapType,
|
||||
}
|
||||
|
||||
tmpl, err := template.New("golang.go.tmpl").Funcs(fnMap).ParseGlob("templates/*.go.tmpl")
|
||||
|
@ -336,7 +331,6 @@ func main() {
|
|||
}
|
||||
err = tmpl.Execute(f, v)
|
||||
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -354,4 +348,3 @@ func main() {
|
|||
tests.Execute(testF, v)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ type Sizer interface {
|
|||
}
|
||||
|
||||
// CanSend takes a packet and makes CAN framing data.
|
||||
func CanSend(p Packet) (id uint32, data []byte, err error) {
|
||||
func ToCanFrame(p Packet) (id uint32, data []byte, err error) {
|
||||
|
||||
id, err = p.CANId()
|
||||
if err != nil {
|
||||
|
@ -71,29 +71,86 @@ func CanSend(p Packet) (id uint32, data []byte, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// ---- JSON encoding business ----
|
||||
// ---- other wire encoding business ----
|
||||
|
||||
type JSONPacket struct {
|
||||
Id uint32
|
||||
Data json.RawMessage
|
||||
// internal structure for partially decoding json object.
|
||||
type jsonRawEvent struct {
|
||||
Timestamp float64
|
||||
Id uint32
|
||||
Name string
|
||||
Data json.RawMessage
|
||||
}
|
||||
|
||||
func ToJson(p Packet) (*JSONPacket, error) {
|
||||
|
||||
d, err := json.Marshal(p)
|
||||
// BusEvent is a timestamped Skylab packet designed to be serialized.
|
||||
type BusEvent struct {
|
||||
Timestamp float64 `json:"ts"`
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Data Packet `json:"data"`
|
||||
}
|
||||
|
||||
// FIXME: handle Name field.
|
||||
func (e *BusEvent) MarshalJSON() (b []byte, err error) {
|
||||
// create the underlying raw event
|
||||
j := &jsonRawEvent{
|
||||
Timestamp: e.Timestamp,
|
||||
Id: uint32(e.Id),
|
||||
}
|
||||
// now we use the magic Packet -> map[string]interface{} function
|
||||
j.Data, err = json.Marshal(e.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, err := p.CANId()
|
||||
return json.Marshal(j)
|
||||
|
||||
}
|
||||
|
||||
func (e *BusEvent) UnmarshalJSON(b []byte) error {
|
||||
var jRaw *jsonRawEvent
|
||||
|
||||
err := json.Unmarshal(b, jRaw)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.Timestamp = jRaw.Timestamp
|
||||
e.Id = uint64(jRaw.Id)
|
||||
e.Data, err = FromJson(jRaw.Id, jRaw.Data)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME: handle name field.
|
||||
func (e *BusEvent) MarshalMsg(b []byte) ([]byte, error) {
|
||||
|
||||
// we need to send the bytes as a []byte instead of
|
||||
// an object like the JSON one (lose self-documenting)
|
||||
data, err := e.Data.MarshalPacket()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawEv := &msgpRawEvent{
|
||||
Timestamp: e.Timestamp,
|
||||
Id: uint32(e.Id),
|
||||
Data: data,
|
||||
}
|
||||
|
||||
jp := &JSONPacket{Id: id, Data: d}
|
||||
return rawEv.MarshalMsg(b)
|
||||
}
|
||||
|
||||
return jp, nil
|
||||
func (e *BusEvent) UnmarshalMsg(b []byte) ([]byte, error) {
|
||||
rawEv := &msgpRawEvent{}
|
||||
remain, err := rawEv.UnmarshalMsg(b)
|
||||
if err != nil {
|
||||
return remain, err
|
||||
}
|
||||
e.Timestamp = rawEv.Timestamp
|
||||
e.Id = uint64(rawEv.Id)
|
||||
e.Data, err = FromCanFrame(rawEv.Id, rawEv.Data)
|
||||
|
||||
return remain, err
|
||||
}
|
||||
|
||||
// we need to be able to parse the JSON as well. this is done using the
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
18
skylab/skylab_msgp.go
Normal file
18
skylab/skylab_msgp.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package skylab
|
||||
|
||||
//go:generate msgp -unexported
|
||||
|
||||
// internal structure for handling
|
||||
type msgpRawEvent struct {
|
||||
Timestamp float64 `msg:"ts"`
|
||||
Id uint32 `msg:"id"`
|
||||
Data []byte `msg:"data"`
|
||||
}
|
||||
|
||||
// internal structure to represent a raw can packet over the network.
|
||||
// this is what's sent over the solar car to lead xbee connection
|
||||
// for brevity while still having some robustness.
|
||||
type msgpRawPacket struct {
|
||||
Id uint32 `msg:"id"`
|
||||
Data []byte `msg:"data"`
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package gotelem
|
||||
package skylab
|
||||
|
||||
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||
|
||||
|
@ -7,7 +7,7 @@ import (
|
|||
)
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *CanFilter) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
func (z *msgpRawEvent) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
var field []byte
|
||||
_ = field
|
||||
var zb0001 uint32
|
||||
|
@ -24,181 +24,24 @@ func (z *CanFilter) DecodeMsg(dc *msgp.Reader) (err error) {
|
|||
return
|
||||
}
|
||||
switch msgp.UnsafeString(field) {
|
||||
case "Id":
|
||||
case "ts":
|
||||
z.Timestamp, err = dc.ReadFloat64()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Timestamp")
|
||||
return
|
||||
}
|
||||
case "id":
|
||||
z.Id, err = dc.ReadUint32()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Id")
|
||||
return
|
||||
}
|
||||
case "Mask":
|
||||
z.Mask, err = dc.ReadUint32()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Mask")
|
||||
return
|
||||
}
|
||||
case "Inverted":
|
||||
z.Inverted, err = dc.ReadBool()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Inverted")
|
||||
return
|
||||
}
|
||||
default:
|
||||
err = dc.Skip()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z CanFilter) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
// map header, size 3
|
||||
// write "Id"
|
||||
err = en.Append(0x83, 0xa2, 0x49, 0x64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteUint32(z.Id)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Id")
|
||||
return
|
||||
}
|
||||
// write "Mask"
|
||||
err = en.Append(0xa4, 0x4d, 0x61, 0x73, 0x6b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteUint32(z.Mask)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Mask")
|
||||
return
|
||||
}
|
||||
// write "Inverted"
|
||||
err = en.Append(0xa8, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteBool(z.Inverted)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Inverted")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z CanFilter) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
// map header, size 3
|
||||
// string "Id"
|
||||
o = append(o, 0x83, 0xa2, 0x49, 0x64)
|
||||
o = msgp.AppendUint32(o, z.Id)
|
||||
// string "Mask"
|
||||
o = append(o, 0xa4, 0x4d, 0x61, 0x73, 0x6b)
|
||||
o = msgp.AppendUint32(o, z.Mask)
|
||||
// string "Inverted"
|
||||
o = append(o, 0xa8, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64)
|
||||
o = msgp.AppendBool(o, z.Inverted)
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *CanFilter) 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 "Mask":
|
||||
z.Mask, bts, err = msgp.ReadUint32Bytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Mask")
|
||||
return
|
||||
}
|
||||
case "Inverted":
|
||||
z.Inverted, bts, err = msgp.ReadBoolBytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Inverted")
|
||||
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 CanFilter) Msgsize() (s int) {
|
||||
s = 1 + 3 + msgp.Uint32Size + 5 + msgp.Uint32Size + 9 + msgp.BoolSize
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *Frame) 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":
|
||||
case "data":
|
||||
z.Data, err = dc.ReadBytes(z.Data)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Data")
|
||||
return
|
||||
}
|
||||
case "Kind":
|
||||
{
|
||||
var zb0002 uint8
|
||||
zb0002, err = dc.ReadUint8()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Kind")
|
||||
return
|
||||
}
|
||||
z.Kind = Kind(zb0002)
|
||||
}
|
||||
default:
|
||||
err = dc.Skip()
|
||||
if err != nil {
|
||||
|
@ -211,10 +54,20 @@ func (z *Frame) DecodeMsg(dc *msgp.Reader) (err error) {
|
|||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z *Frame) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
func (z *msgpRawEvent) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
// map header, size 3
|
||||
// write "Id"
|
||||
err = en.Append(0x83, 0xa2, 0x49, 0x64)
|
||||
// write "ts"
|
||||
err = en.Append(0x83, 0xa2, 0x74, 0x73)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteFloat64(z.Timestamp)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Timestamp")
|
||||
return
|
||||
}
|
||||
// write "id"
|
||||
err = en.Append(0xa2, 0x69, 0x64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -223,8 +76,8 @@ func (z *Frame) EncodeMsg(en *msgp.Writer) (err error) {
|
|||
err = msgp.WrapError(err, "Id")
|
||||
return
|
||||
}
|
||||
// write "Data"
|
||||
err = en.Append(0xa4, 0x44, 0x61, 0x74, 0x61)
|
||||
// write "data"
|
||||
err = en.Append(0xa4, 0x64, 0x61, 0x74, 0x61)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -233,37 +86,27 @@ func (z *Frame) EncodeMsg(en *msgp.Writer) (err error) {
|
|||
err = msgp.WrapError(err, "Data")
|
||||
return
|
||||
}
|
||||
// write "Kind"
|
||||
err = en.Append(0xa4, 0x4b, 0x69, 0x6e, 0x64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = en.WriteUint8(uint8(z.Kind))
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Kind")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z *Frame) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
func (z *msgpRawEvent) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
// map header, size 3
|
||||
// string "Id"
|
||||
o = append(o, 0x83, 0xa2, 0x49, 0x64)
|
||||
// string "ts"
|
||||
o = append(o, 0x83, 0xa2, 0x74, 0x73)
|
||||
o = msgp.AppendFloat64(o, z.Timestamp)
|
||||
// string "id"
|
||||
o = append(o, 0xa2, 0x69, 0x64)
|
||||
o = msgp.AppendUint32(o, z.Id)
|
||||
// string "Data"
|
||||
o = append(o, 0xa4, 0x44, 0x61, 0x74, 0x61)
|
||||
// string "data"
|
||||
o = append(o, 0xa4, 0x64, 0x61, 0x74, 0x61)
|
||||
o = msgp.AppendBytes(o, z.Data)
|
||||
// string "Kind"
|
||||
o = append(o, 0xa4, 0x4b, 0x69, 0x6e, 0x64)
|
||||
o = msgp.AppendUint8(o, uint8(z.Kind))
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *Frame) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
func (z *msgpRawEvent) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
var field []byte
|
||||
_ = field
|
||||
var zb0001 uint32
|
||||
|
@ -280,28 +123,24 @@ func (z *Frame) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
|||
return
|
||||
}
|
||||
switch msgp.UnsafeString(field) {
|
||||
case "Id":
|
||||
case "ts":
|
||||
z.Timestamp, bts, err = msgp.ReadFloat64Bytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Timestamp")
|
||||
return
|
||||
}
|
||||
case "id":
|
||||
z.Id, bts, err = msgp.ReadUint32Bytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Id")
|
||||
return
|
||||
}
|
||||
case "Data":
|
||||
case "data":
|
||||
z.Data, bts, err = msgp.ReadBytesBytes(bts, z.Data)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Data")
|
||||
return
|
||||
}
|
||||
case "Kind":
|
||||
{
|
||||
var zb0002 uint8
|
||||
zb0002, bts, err = msgp.ReadUint8Bytes(bts)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Kind")
|
||||
return
|
||||
}
|
||||
z.Kind = Kind(zb0002)
|
||||
}
|
||||
default:
|
||||
bts, err = msgp.Skip(bts)
|
||||
if err != nil {
|
||||
|
@ -315,59 +154,135 @@ func (z *Frame) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
|||
}
|
||||
|
||||
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||
func (z *Frame) Msgsize() (s int) {
|
||||
s = 1 + 3 + msgp.Uint32Size + 5 + msgp.BytesPrefixSize + len(z.Data) + 5 + msgp.Uint8Size
|
||||
func (z *msgpRawEvent) Msgsize() (s int) {
|
||||
s = 1 + 3 + msgp.Float64Size + 3 + msgp.Uint32Size + 5 + msgp.BytesPrefixSize + len(z.Data)
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeMsg implements msgp.Decodable
|
||||
func (z *Kind) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
{
|
||||
var zb0001 uint8
|
||||
zb0001, err = dc.ReadUint8()
|
||||
func (z *msgpRawPacket) 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
|
||||
}
|
||||
(*z) = Kind(zb0001)
|
||||
switch msgp.UnsafeString(field) {
|
||||
case "id":
|
||||
z.Id, err = dc.ReadUint32()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Id")
|
||||
return
|
||||
}
|
||||
case "data":
|
||||
z.Data, err = dc.ReadBytes(z.Data)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Data")
|
||||
return
|
||||
}
|
||||
default:
|
||||
err = dc.Skip()
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EncodeMsg implements msgp.Encodable
|
||||
func (z Kind) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
err = en.WriteUint8(uint8(z))
|
||||
func (z *msgpRawPacket) EncodeMsg(en *msgp.Writer) (err error) {
|
||||
// map header, size 2
|
||||
// write "id"
|
||||
err = en.Append(0x82, 0xa2, 0x69, 0x64)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err)
|
||||
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.Data)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Data")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalMsg implements msgp.Marshaler
|
||||
func (z Kind) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
func (z *msgpRawPacket) MarshalMsg(b []byte) (o []byte, err error) {
|
||||
o = msgp.Require(b, z.Msgsize())
|
||||
o = msgp.AppendUint8(o, uint8(z))
|
||||
// map header, size 2
|
||||
// string "id"
|
||||
o = append(o, 0x82, 0xa2, 0x69, 0x64)
|
||||
o = msgp.AppendUint32(o, z.Id)
|
||||
// string "data"
|
||||
o = append(o, 0xa4, 0x64, 0x61, 0x74, 0x61)
|
||||
o = msgp.AppendBytes(o, z.Data)
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalMsg implements msgp.Unmarshaler
|
||||
func (z *Kind) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
{
|
||||
var zb0001 uint8
|
||||
zb0001, bts, err = msgp.ReadUint8Bytes(bts)
|
||||
func (z *msgpRawPacket) 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
|
||||
}
|
||||
(*z) = Kind(zb0001)
|
||||
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.Data, bts, err = msgp.ReadBytesBytes(bts, z.Data)
|
||||
if err != nil {
|
||||
err = msgp.WrapError(err, "Data")
|
||||
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 Kind) Msgsize() (s int) {
|
||||
s = msgp.Uint8Size
|
||||
func (z *msgpRawPacket) Msgsize() (s int) {
|
||||
s = 1 + 3 + msgp.Uint32Size + 5 + msgp.BytesPrefixSize + len(z.Data)
|
||||
return
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package gotelem
|
||||
package skylab
|
||||
|
||||
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
|
||||
|
||||
|
@ -9,8 +9,8 @@ import (
|
|||
"github.com/tinylib/msgp/msgp"
|
||||
)
|
||||
|
||||
func TestMarshalUnmarshalCanFilter(t *testing.T) {
|
||||
v := CanFilter{}
|
||||
func TestMarshalUnmarshalmsgpRawEvent(t *testing.T) {
|
||||
v := msgpRawEvent{}
|
||||
bts, err := v.MarshalMsg(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -32,8 +32,8 @@ func TestMarshalUnmarshalCanFilter(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalMsgCanFilter(b *testing.B) {
|
||||
v := CanFilter{}
|
||||
func BenchmarkMarshalMsgmsgpRawEvent(b *testing.B) {
|
||||
v := msgpRawEvent{}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -41,8 +41,8 @@ func BenchmarkMarshalMsgCanFilter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendMsgCanFilter(b *testing.B) {
|
||||
v := CanFilter{}
|
||||
func BenchmarkAppendMsgmsgpRawEvent(b *testing.B) {
|
||||
v := msgpRawEvent{}
|
||||
bts := make([]byte, 0, v.Msgsize())
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
b.SetBytes(int64(len(bts)))
|
||||
|
@ -53,8 +53,8 @@ func BenchmarkAppendMsgCanFilter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalCanFilter(b *testing.B) {
|
||||
v := CanFilter{}
|
||||
func BenchmarkUnmarshalmsgpRawEvent(b *testing.B) {
|
||||
v := msgpRawEvent{}
|
||||
bts, _ := v.MarshalMsg(nil)
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(bts)))
|
||||
|
@ -67,17 +67,17 @@ func BenchmarkUnmarshalCanFilter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeCanFilter(t *testing.T) {
|
||||
v := CanFilter{}
|
||||
func TestEncodeDecodemsgpRawEvent(t *testing.T) {
|
||||
v := msgpRawEvent{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
|
||||
m := v.Msgsize()
|
||||
if buf.Len() > m {
|
||||
t.Log("WARNING: TestEncodeDecodeCanFilter Msgsize() is inaccurate")
|
||||
t.Log("WARNING: TestEncodeDecodemsgpRawEvent Msgsize() is inaccurate")
|
||||
}
|
||||
|
||||
vn := CanFilter{}
|
||||
vn := msgpRawEvent{}
|
||||
err := msgp.Decode(&buf, &vn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -91,8 +91,8 @@ func TestEncodeDecodeCanFilter(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeCanFilter(b *testing.B) {
|
||||
v := CanFilter{}
|
||||
func BenchmarkEncodemsgpRawEvent(b *testing.B) {
|
||||
v := msgpRawEvent{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
|
@ -105,8 +105,8 @@ func BenchmarkEncodeCanFilter(b *testing.B) {
|
|||
en.Flush()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeCanFilter(b *testing.B) {
|
||||
v := CanFilter{}
|
||||
func BenchmarkDecodemsgpRawEvent(b *testing.B) {
|
||||
v := msgpRawEvent{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
|
@ -122,8 +122,8 @@ func BenchmarkDecodeCanFilter(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalFrame(t *testing.T) {
|
||||
v := Frame{}
|
||||
func TestMarshalUnmarshalmsgpRawPacket(t *testing.T) {
|
||||
v := msgpRawPacket{}
|
||||
bts, err := v.MarshalMsg(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -145,8 +145,8 @@ func TestMarshalUnmarshalFrame(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshalMsgFrame(b *testing.B) {
|
||||
v := Frame{}
|
||||
func BenchmarkMarshalMsgmsgpRawPacket(b *testing.B) {
|
||||
v := msgpRawPacket{}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -154,8 +154,8 @@ func BenchmarkMarshalMsgFrame(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendMsgFrame(b *testing.B) {
|
||||
v := Frame{}
|
||||
func BenchmarkAppendMsgmsgpRawPacket(b *testing.B) {
|
||||
v := msgpRawPacket{}
|
||||
bts := make([]byte, 0, v.Msgsize())
|
||||
bts, _ = v.MarshalMsg(bts[0:0])
|
||||
b.SetBytes(int64(len(bts)))
|
||||
|
@ -166,8 +166,8 @@ func BenchmarkAppendMsgFrame(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshalFrame(b *testing.B) {
|
||||
v := Frame{}
|
||||
func BenchmarkUnmarshalmsgpRawPacket(b *testing.B) {
|
||||
v := msgpRawPacket{}
|
||||
bts, _ := v.MarshalMsg(nil)
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(bts)))
|
||||
|
@ -180,17 +180,17 @@ func BenchmarkUnmarshalFrame(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeFrame(t *testing.T) {
|
||||
v := Frame{}
|
||||
func TestEncodeDecodemsgpRawPacket(t *testing.T) {
|
||||
v := msgpRawPacket{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
|
||||
m := v.Msgsize()
|
||||
if buf.Len() > m {
|
||||
t.Log("WARNING: TestEncodeDecodeFrame Msgsize() is inaccurate")
|
||||
t.Log("WARNING: TestEncodeDecodemsgpRawPacket Msgsize() is inaccurate")
|
||||
}
|
||||
|
||||
vn := Frame{}
|
||||
vn := msgpRawPacket{}
|
||||
err := msgp.Decode(&buf, &vn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -204,8 +204,8 @@ func TestEncodeDecodeFrame(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeFrame(b *testing.B) {
|
||||
v := Frame{}
|
||||
func BenchmarkEncodemsgpRawPacket(b *testing.B) {
|
||||
v := msgpRawPacket{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
||||
|
@ -218,8 +218,8 @@ func BenchmarkEncodeFrame(b *testing.B) {
|
|||
en.Flush()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeFrame(b *testing.B) {
|
||||
v := Frame{}
|
||||
func BenchmarkDecodemsgpRawPacket(b *testing.B) {
|
||||
v := msgpRawPacket{}
|
||||
var buf bytes.Buffer
|
||||
msgp.Encode(&buf, &v)
|
||||
b.SetBytes(int64(buf.Len()))
|
|
@ -11,7 +11,7 @@ type {{$bfname}} struct {
|
|||
{{- end}}
|
||||
}
|
||||
|
||||
func (p *{{$bfname}}) Marshal() byte {
|
||||
func (p *{{$bfname}}) MarshalByte() byte {
|
||||
var b byte
|
||||
{{- range $idx, $el := .Bits}}
|
||||
{{- $bitName := camelCase $el.Name true}}
|
||||
|
@ -22,7 +22,7 @@ func (p *{{$bfname}}) Marshal() byte {
|
|||
return b
|
||||
}
|
||||
|
||||
func (p *{{$bfname}}) Unmarshal(b byte) {
|
||||
func (p *{{$bfname}}) UnmarshalByte(b byte) {
|
||||
{{- range $idx, $el := .Bits}}
|
||||
{{- $bitName := camelCase $el.Name true }}
|
||||
p.{{$bitName}} = (b & (1 << {{ $idx }})) != 0
|
||||
|
@ -114,7 +114,7 @@ var idMap = map[uint32]bool{
|
|||
// If the CAN ID is unknown, it will return an error.
|
||||
func FromCanFrame(id uint32, data []byte) (Packet, error) {
|
||||
if !idMap[id] {
|
||||
return nil, errors.New("Unknown Id")
|
||||
return nil, errors.New("unknown id")
|
||||
}
|
||||
switch id {
|
||||
{{- range $p := .Packets }}
|
||||
|
@ -133,34 +133,32 @@ func FromCanFrame(id uint32, data []byte) (Packet, error) {
|
|||
{{- end}}
|
||||
}
|
||||
|
||||
return nil, errors.New("failed to match Id, something is really wrong!")
|
||||
return nil, errors.New("failed to match Id, something is really wrong")
|
||||
}
|
||||
|
||||
func FromJson (raw []byte) (Packet, error) {
|
||||
// attempt to parse the JSON to a JSONPacket
|
||||
jp := &JSONPacket{}
|
||||
err := json.Unmarshal(raw, jp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
func FromJson (id uint32, raw []byte) (Packet, error) {
|
||||
if !idMap[id] {
|
||||
return nil, errors.New("unknown id")
|
||||
}
|
||||
switch jp.Id {
|
||||
switch id {
|
||||
{{- range $p := .Packets }}
|
||||
{{- if $p.Repeat }}
|
||||
case {{ Nx (int $p.Id) $p.Repeat $p.Offset | mapf "0x%X" | strJoin ", " -}}:
|
||||
var res = &{{camelCase $p.Name true}}{}
|
||||
err := json.Unmarshal(jp.Data, res)
|
||||
res.Idx = jp.Id - {{ $p.Id | printf "0x%X" }}
|
||||
err := json.Unmarshal(raw, res)
|
||||
res.Idx = id - {{ $p.Id | printf "0x%X" }}
|
||||
return res, err
|
||||
{{- else }}
|
||||
case {{ $p.Id | printf "0x%X" }}:
|
||||
var res = &{{camelCase $p.Name true}}{}
|
||||
err := json.Unmarshal(jp.Data, res)
|
||||
err := json.Unmarshal(raw, res)
|
||||
return res, err
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
return nil, errors.New("aaa")
|
||||
return nil, errors.New("failed to match id")
|
||||
}
|
||||
|
||||
{{range .Packets -}}
|
||||
|
|
|
@ -23,17 +23,14 @@ func TestMarshalUnmarshal{{$structName}}(t *testing.T) {
|
|||
func TestJSON{{$structName}}(t *testing.T) {
|
||||
|
||||
v := &{{$structName}}{}
|
||||
jp, err := ToJson(v)
|
||||
|
||||
rawData, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rawData, err := json.Marshal(jp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p, err := FromJson(rawData)
|
||||
id, _ := v.CANId()
|
||||
p, err := FromJson(id, rawData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
package gotelem
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/kschamplin/gotelem/skylab"
|
||||
)
|
||||
|
||||
// CanWriter
|
||||
type CanWriter struct {
|
||||
output *os.File
|
||||
cd CANDumpEntry
|
||||
jsonBuf []byte
|
||||
}
|
||||
|
||||
// send writes the frame to the file.
|
||||
func (cw *CanWriter) Send(f *Frame) (err error) {
|
||||
cw.cd.Timestamp = float64(time.Now().Unix())
|
||||
|
||||
cw.cd.Id = uint64(f.Id)
|
||||
|
||||
cw.cd.Data, err = skylab.FromCanFrame(f.Id, f.Data)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
out, err := json.Marshal(cw.cd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(cw.output, string(out))
|
||||
return err
|
||||
}
|
||||
|
||||
func (cw *CanWriter) Close() error {
|
||||
return cw.output.Close()
|
||||
}
|
||||
|
||||
func OpenCanWriter(name string) (*CanWriter, error) {
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cw := &CanWriter{
|
||||
output: f,
|
||||
}
|
||||
return cw, nil
|
||||
}
|
||||
|
||||
type CANDumpEntry struct {
|
||||
Timestamp float64 `json:"ts"`
|
||||
Id uint64 `json:"id"`
|
||||
Data skylab.Packet `json:"data"`
|
||||
}
|
Loading…
Reference in a new issue