skylab: rework interface

This commit is contained in:
saji 2023-05-28 19:39:03 -05:00
parent 96149ee38b
commit 2dceb3927e
17 changed files with 921 additions and 1357 deletions

View file

@ -2,104 +2,29 @@ package gotelem
import ( import (
"errors" "errors"
"fmt"
"sync" "sync"
"github.com/kschamplin/gotelem/skylab"
"golang.org/x/exp/slog" "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 { 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 logger *slog.Logger
lock sync.RWMutex lock sync.RWMutex
bufsize int // size of chan buffer in elements. bufsize int // size of chan buffer in elements.
} }
func NewBroker(bufsize int, logger *slog.Logger) *JBroker { func NewBroker(bufsize int, logger *slog.Logger) *JBroker {
return &JBroker{ return &JBroker{
subs: make(map[string]chan CANDumpEntry), subs: make(map[string]chan skylab.BusEvent),
logger: logger, logger: logger,
bufsize: bufsize, 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. // get rw lock.
b.lock.Lock() b.lock.Lock()
defer b.lock.Unlock() 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") return nil, errors.New("name already in use")
} }
b.logger.Info("new subscriber", "name", name) b.logger.Info("new subscriber", "name", name)
ch = make(chan CANDumpEntry, b.bufsize) ch = make(chan skylab.BusEvent, b.bufsize)
b.subs[name] = ch b.subs[name] = ch
return return
@ -121,7 +46,7 @@ func (b *JBroker) Unsubscribe(name string) {
delete(b.subs, name) delete(b.subs, name)
} }
func (b *JBroker) Publish(sender string, message CANDumpEntry) { func (b *JBroker) Publish(sender string, message skylab.BusEvent) {
b.lock.RLock() b.lock.RLock()
defer b.lock.RUnlock() defer b.lock.RUnlock()
for name, ch := range b.subs { for name, ch := range b.subs {

View file

@ -3,18 +3,16 @@ package cli
import ( import (
"fmt" "fmt"
imgui "github.com/AllenDang/cimgui-go"
"github.com/kschamplin/gotelem" "github.com/kschamplin/gotelem"
"github.com/kschamplin/gotelem/mprpc" "github.com/kschamplin/gotelem/mprpc"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
imgui "github.com/AllenDang/cimgui-go"
) )
func init() { func init() {
subCmds = append(subCmds, clientCmd) subCmds = append(subCmds, clientCmd)
} }
var clientCmd = &cli.Command{ var clientCmd = &cli.Command{
Name: "client", Name: "client",
Aliases: []string{"c"}, Aliases: []string{"c"},
@ -33,7 +31,6 @@ Connects to a gotelem server or relay. Can be used to
Action: client, Action: client,
} }
func loop() { func loop() {
imgui.ShowDemoWindow() imgui.ShowDemoWindow()
} }
@ -45,13 +42,8 @@ func client(ctx *cli.Context) error {
return nil return nil
} }
// the client should connect to a TCP server and listen to packets. // 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) fmt.Printf("got frame, %v\n", f)
return nil, nil return nil, nil
} }
var initialRPCHandlers = map[string]mprpc.ServiceFunc{
"can": mprpc.MakeService(CANFrameHandler),
}

View file

@ -37,11 +37,9 @@ var serveCmd = &cli.Command{
Action: serve, Action: serve,
} }
// FIXME: naming // FIXME: naming
// this is a server handler for i.e tcp socket, http server, socketCAN, xbee, // this is a server handler for i.e tcp socket, http server, socketCAN, xbee,
// etc. we can register them in init() functions. // 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 { type service interface {
fmt.Stringer fmt.Stringer
@ -58,12 +56,6 @@ var serveThings = []service{
&rpcService{}, &rpcService{},
} }
func deriveLogger (oldLogger *slog.Logger, svc service) (newLogger *slog.Logger) {
newLogger = oldLogger.With("svc", svc.String())
return
}
func serve(cCtx *cli.Context) error { func serve(cCtx *cli.Context) error {
// TODO: output both to stderr and a file. // TODO: output both to stderr and a file.
logger := slog.New(slog.NewTextHandler(os.Stderr)) logger := slog.New(slog.NewTextHandler(os.Stderr))
@ -85,14 +77,11 @@ func serve(cCtx *cli.Context) error {
}(svc, logger) }(svc, logger)
} }
wg.Wait() wg.Wait()
return nil return nil
} }
type rpcService struct { type rpcService struct {
} }
@ -162,7 +151,6 @@ func (c *CanLoggerService) String() string {
func (c *CanLoggerService) Status() { 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") rxCh, err := broker.Subscribe("canDump")
if err != nil { if err != nil {
@ -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 // 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. // based on the url provided in the xbee flag. see the description for details.
type XBeeService struct { type XBeeService struct {
@ -207,7 +194,6 @@ func (x *XBeeService) String() string {
func (x *XBeeService) Status() { func (x *XBeeService) Status() {
} }
func (x *XBeeService) Start(cCtx *cli.Context, broker *gotelem.JBroker, logger *slog.Logger) (err error) { func (x *XBeeService) Start(cCtx *cli.Context, broker *gotelem.JBroker, logger *slog.Logger) (err error) {
if cCtx.String("xbee") == "" { if cCtx.String("xbee") == "" {
logger.Info("not using xbee") logger.Info("not using xbee")
@ -245,7 +231,5 @@ func (x *XBeeService) Start(cCtx *cli.Context, broker *gotelem.JBroker, logger *
} }
} }
} }
} }

View file

@ -37,10 +37,9 @@ func init() {
subCmds = append(subCmds, socketCANCmd) subCmds = append(subCmds, socketCANCmd)
} }
type socketCANService struct { type socketCANService struct {
name string name string
sock socketcan.CanSocket sock *socketcan.CanSocket
} }
func (s *socketCANService) Status() { func (s *socketCANService) Status() {
@ -66,13 +65,13 @@ func (s *socketCANService) Start(cCtx *cli.Context, broker *gotelem.JBroker, log
go vcanTest(cCtx.String("can")) go vcanTest(cCtx.String("can"))
} }
sock, err := socketcan.NewCanSocket(cCtx.String("can")) s.sock, err = socketcan.NewCanSocket(cCtx.String("can"))
if err != nil { if err != nil {
logger.Error("error opening socket", "err", err) logger.Error("error opening socket", "err", err)
return return
} }
defer sock.Close() defer s.sock.Close()
s.name = sock.Name() s.name = s.sock.Name()
// connect to the broker // connect to the broker
rxCh, err := broker.Subscribe("socketCAN") rxCh, err := broker.Subscribe("socketCAN")
@ -81,13 +80,12 @@ func (s *socketCANService) Start(cCtx *cli.Context, broker *gotelem.JBroker, log
} }
defer broker.Unsubscribe("socketCAN") defer broker.Unsubscribe("socketCAN")
// make a channel to receive socketCAN frames. // make a channel to receive socketCAN frames.
rxCan := make(chan gotelem.Frame) rxCan := make(chan gotelem.Frame)
go func() { go func() {
for { for {
pkt, err := sock.Recv() pkt, err := s.sock.Recv()
if err != nil { if err != nil {
logger.Warn("error receiving CAN packet", "err", err) logger.Warn("error receiving CAN packet", "err", err)
} }
@ -100,12 +98,12 @@ func (s *socketCANService) Start(cCtx *cli.Context, broker *gotelem.JBroker, log
select { select {
case msg := <-rxCh: case msg := <-rxCh:
id, d, _ := skylab.CanSend(msg.Data) id, d, _ := skylab.ToCanFrame(msg.Data)
frame.Id = id frame.Id = id
frame.Data = d frame.Data = d
sock.Send(&frame) s.sock.Send(&frame)
case msg := <-rxCan: case msg := <-rxCan:
p, err := skylab.FromCanFrame(msg.Id, msg.Data) p, err := skylab.FromCanFrame(msg.Id, msg.Data)
@ -113,7 +111,7 @@ func (s *socketCANService) Start(cCtx *cli.Context, broker *gotelem.JBroker, log
logger.Warn("error parsing can packet", "id", msg.Id) logger.Warn("error parsing can packet", "id", msg.Id)
continue continue
} }
cde := gotelem.CANDumpEntry{ cde := skylab.BusEvent{
Timestamp: float64(time.Now().UnixNano()) / 1e9, Timestamp: float64(time.Now().UnixNano()) / 1e9,
Id: uint64(msg.Id), Id: uint64(msg.Id),
Data: p, Data: p,
@ -161,14 +159,13 @@ func vcanTest(devname string) {
Id: 0.2, Id: 0.2,
} }
id, data, err := skylab.CanSend(&testPkt) id, data, err := skylab.ToCanFrame(&testPkt)
testFrame := gotelem.Frame{ testFrame := gotelem.Frame{
Id: id, Id: id,
Data: data, Data: data,
Kind: gotelem.CanSFFFrame, Kind: gotelem.CanSFFFrame,
} }
for { for {
slog.Info("sending test packet") slog.Info("sending test packet")
sock.Send(&testFrame) sock.Send(&testFrame)

View file

@ -12,7 +12,6 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/kschamplin/gotelem"
"github.com/kschamplin/gotelem/skylab" "github.com/kschamplin/gotelem/skylab"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -92,7 +91,7 @@ func run(ctx *cli.Context) (err error) {
segments := strings.Split(dumpLine, " ") 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. // this is cursed but easiest way to get a float from a string.
fmt.Sscanf(segments[0], "(%g)", &cd.Timestamp) fmt.Sscanf(segments[0], "(%g)", &cd.Timestamp)

View file

@ -6,7 +6,6 @@
// by writing "adapters" to various devices/formats (xbee, sqlite, network socket, socketcan) // by writing "adapters" to various devices/formats (xbee, sqlite, network socket, socketcan)
package gotelem package gotelem
// Frame represents a protocol-agnostic CAN frame. The Id can be standard or extended, // Frame represents a protocol-agnostic CAN frame. The Id can be standard or extended,
// but if it is extended, the Kind should be EFF. // but if it is extended, the Kind should be EFF.
type Frame struct { type Frame struct {
@ -15,7 +14,6 @@ type Frame struct {
Kind Kind Kind Kind
} }
//go:generate msgp
type CANFrame interface { type CANFrame interface {
Id() uint32 Id() uint32
Data() []byte Data() []byte
@ -58,4 +56,3 @@ type CanTransciever interface {
CanSink CanSink
CanSource CanSource
} }

1
go.mod
View file

@ -20,4 +20,5 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/testify v1.8.0 // indirect github.com/stretchr/testify v1.8.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

View file

@ -19,7 +19,6 @@ import (
type SkylabFile struct { type SkylabFile struct {
Packets []PacketDef Packets []PacketDef
Boards []BoardSpec Boards []BoardSpec
} }
type BoardSpec struct { type BoardSpec struct {
@ -80,6 +79,10 @@ var typeSizeMap = map[string]uint{
"bitfield": 1, "bitfield": 1,
} }
func MapType(ctype string) string {
return typeMap[ctype]
}
func (d *DataField) ToStructMember(parentName string) string { func (d *DataField) ToStructMember(parentName string) string {
if d.Type == "bitfield" { if d.Type == "bitfield" {
@ -96,7 +99,7 @@ func (d *DataField) MakeMarshal(offset int) string {
if d.Type == "uint8_t" || d.Type == "int8_t" { if d.Type == "uint8_t" || d.Type == "int8_t" {
return fmt.Sprintf("b[%d] = p.%s", offset, fieldName) return fmt.Sprintf("b[%d] = p.%s", offset, fieldName)
} else if d.Type == "bitfield" { } 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" { } else if d.Type == "float" {
return fmt.Sprintf("float32ToBytes(b[%d:], p.%s, false)", offset, fieldName) return fmt.Sprintf("float32ToBytes(b[%d:], p.%s, false)", offset, fieldName)
@ -114,14 +117,13 @@ func (d *DataField) MakeMarshal(offset int) string {
return "panic(\"failed to do it\")\n" return "panic(\"failed to do it\")\n"
} }
func (d *DataField) MakeUnmarshal(offset int) string { func (d *DataField) MakeUnmarshal(offset int) string {
fieldName := toCamelInitCase(d.Name, true) fieldName := toCamelInitCase(d.Name, true)
if d.Type == "uint8_t" || d.Type == "int8_t" { if d.Type == "uint8_t" || d.Type == "int8_t" {
return fmt.Sprintf("p.%s = b[%d]", fieldName, offset) return fmt.Sprintf("p.%s = b[%d]", fieldName, offset)
} else if d.Type == "bitfield" { } 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" { } else if d.Type == "float" {
return fmt.Sprintf("p.%s = float32FromBytes(b[%d:], false)", fieldName, offset) 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") panic("unhandled type")
} }
func (p PacketDef) CalcSize() int { func (p PacketDef) CalcSize() int {
// makes a function that returns the size of the code. // makes a function that returns the size of the code.
@ -153,7 +153,6 @@ func (p PacketDef) CalcSize() int {
return size return size
} }
func (p PacketDef) MakeMarshal() string { func (p PacketDef) MakeMarshal() string {
var buf strings.Builder var buf strings.Builder
@ -170,14 +169,12 @@ func (p PacketDef) MakeMarshal() string {
offset += int(typeSizeMap[val.Type]) offset += int(typeSizeMap[val.Type])
} }
return buf.String() return buf.String()
} }
func (p PacketDef) MakeUnmarshal() string { func (p PacketDef) MakeUnmarshal() string {
var buf strings.Builder var buf strings.Builder
var offset int = 0 var offset int = 0
for _, val := range p.Data { for _, val := range p.Data {
@ -190,7 +187,6 @@ func (p PacketDef) MakeUnmarshal() string {
return buf.String() return buf.String()
} }
// stolen camelCaser code. initCase = true means CamelCase, false means camelCase // stolen camelCaser code. initCase = true means CamelCase, false means camelCase
func toCamelInitCase(s string, initCase bool) string { func toCamelInitCase(s string, initCase bool) string {
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
@ -241,7 +237,6 @@ func N(start, end int) (stream chan int) {
return return
} }
// Nx takes a start, a quantity, and an offset and returns a stream // 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 // of `times` values which count from start and increment by `offset` each
// time. // time.
@ -259,9 +254,9 @@ func uint32ToInt(i uint32) (o int) {
return int(i) return int(i)
} }
// strJoin is a remapping of strings.Join so that we can use // strJoin is a remapping of strings.Join so that we can use
// it in a pipeline. // it in a pipeline.
//
// {{.Names | strJoin ", " }} // {{.Names | strJoin ", " }}
func strJoin(delim string, elems []string) string { func strJoin(delim string, elems []string) string {
return strings.Join(elems, delim) return strings.Join(elems, delim)
@ -277,7 +272,6 @@ func mapf(format string, els []int) []string {
return resp return resp
} }
func main() { func main() {
// read path as the first arg, glob it for yamls, read each yaml into a skylabFile. // 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. // then take each skylab file, put all the packets into one big array.
@ -321,6 +315,7 @@ func main() {
"int": uint32ToInt, "int": uint32ToInt,
"strJoin": strJoin, "strJoin": strJoin,
"mapf": mapf, "mapf": mapf,
"maptype": MapType,
} }
tmpl, err := template.New("golang.go.tmpl").Funcs(fnMap).ParseGlob("templates/*.go.tmpl") tmpl, err := template.New("golang.go.tmpl").Funcs(fnMap).ParseGlob("templates/*.go.tmpl")
@ -336,7 +331,6 @@ func main() {
} }
err = tmpl.Execute(f, v) err = tmpl.Execute(f, v)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -354,4 +348,3 @@ func main() {
tests.Execute(testF, v) tests.Execute(testF, v)
} }

View file

@ -61,7 +61,7 @@ type Sizer interface {
} }
// CanSend takes a packet and makes CAN framing data. // 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() id, err = p.CANId()
if err != nil { if err != nil {
@ -71,29 +71,86 @@ func CanSend(p Packet) (id uint32, data []byte, err error) {
return return
} }
// ---- JSON encoding business ---- // ---- other wire encoding business ----
type JSONPacket struct { // internal structure for partially decoding json object.
type jsonRawEvent struct {
Timestamp float64
Id uint32 Id uint32
Name string
Data json.RawMessage Data json.RawMessage
} }
func ToJson(p Packet) (*JSONPacket, error) { // BusEvent is a timestamped Skylab packet designed to be serialized.
type BusEvent struct {
d, err := json.Marshal(p) 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 { if err != nil {
return nil, err 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 { if err != nil {
return nil, err 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 // 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
View 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"`
}

View file

@ -1,4 +1,4 @@
package gotelem package skylab
// Code generated by github.com/tinylib/msgp DO NOT EDIT. // Code generated by github.com/tinylib/msgp DO NOT EDIT.
@ -7,7 +7,7 @@ import (
) )
// DecodeMsg implements msgp.Decodable // 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 var field []byte
_ = field _ = field
var zb0001 uint32 var zb0001 uint32
@ -24,181 +24,24 @@ func (z *CanFilter) DecodeMsg(dc *msgp.Reader) (err error) {
return return
} }
switch msgp.UnsafeString(field) { 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() z.Id, err = dc.ReadUint32()
if err != nil { if err != nil {
err = msgp.WrapError(err, "Id") err = msgp.WrapError(err, "Id")
return return
} }
case "Mask": case "data":
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":
z.Data, err = dc.ReadBytes(z.Data) z.Data, err = dc.ReadBytes(z.Data)
if err != nil { if err != nil {
err = msgp.WrapError(err, "Data") err = msgp.WrapError(err, "Data")
return return
} }
case "Kind":
{
var zb0002 uint8
zb0002, err = dc.ReadUint8()
if err != nil {
err = msgp.WrapError(err, "Kind")
return
}
z.Kind = Kind(zb0002)
}
default: default:
err = dc.Skip() err = dc.Skip()
if err != nil { if err != nil {
@ -211,10 +54,20 @@ func (z *Frame) DecodeMsg(dc *msgp.Reader) (err error) {
} }
// EncodeMsg implements msgp.Encodable // 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 // map header, size 3
// write "Id" // write "ts"
err = en.Append(0x83, 0xa2, 0x49, 0x64) 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 { if err != nil {
return return
} }
@ -223,8 +76,8 @@ func (z *Frame) EncodeMsg(en *msgp.Writer) (err error) {
err = msgp.WrapError(err, "Id") err = msgp.WrapError(err, "Id")
return return
} }
// write "Data" // write "data"
err = en.Append(0xa4, 0x44, 0x61, 0x74, 0x61) err = en.Append(0xa4, 0x64, 0x61, 0x74, 0x61)
if err != nil { if err != nil {
return return
} }
@ -233,37 +86,27 @@ func (z *Frame) EncodeMsg(en *msgp.Writer) (err error) {
err = msgp.WrapError(err, "Data") err = msgp.WrapError(err, "Data")
return 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 return
} }
// MarshalMsg implements msgp.Marshaler // 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()) o = msgp.Require(b, z.Msgsize())
// map header, size 3 // map header, size 3
// string "Id" // string "ts"
o = append(o, 0x83, 0xa2, 0x49, 0x64) 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) o = msgp.AppendUint32(o, z.Id)
// string "Data" // string "data"
o = append(o, 0xa4, 0x44, 0x61, 0x74, 0x61) o = append(o, 0xa4, 0x64, 0x61, 0x74, 0x61)
o = msgp.AppendBytes(o, z.Data) o = msgp.AppendBytes(o, z.Data)
// string "Kind"
o = append(o, 0xa4, 0x4b, 0x69, 0x6e, 0x64)
o = msgp.AppendUint8(o, uint8(z.Kind))
return return
} }
// UnmarshalMsg implements msgp.Unmarshaler // 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 var field []byte
_ = field _ = field
var zb0001 uint32 var zb0001 uint32
@ -280,28 +123,24 @@ func (z *Frame) UnmarshalMsg(bts []byte) (o []byte, err error) {
return return
} }
switch msgp.UnsafeString(field) { 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) z.Id, bts, err = msgp.ReadUint32Bytes(bts)
if err != nil { if err != nil {
err = msgp.WrapError(err, "Id") err = msgp.WrapError(err, "Id")
return return
} }
case "Data": case "data":
z.Data, bts, err = msgp.ReadBytesBytes(bts, z.Data) z.Data, bts, err = msgp.ReadBytesBytes(bts, z.Data)
if err != nil { if err != nil {
err = msgp.WrapError(err, "Data") err = msgp.WrapError(err, "Data")
return 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: default:
bts, err = msgp.Skip(bts) bts, err = msgp.Skip(bts)
if err != nil { 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 // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *Frame) Msgsize() (s int) { func (z *msgpRawEvent) Msgsize() (s int) {
s = 1 + 3 + msgp.Uint32Size + 5 + msgp.BytesPrefixSize + len(z.Data) + 5 + msgp.Uint8Size s = 1 + 3 + msgp.Float64Size + 3 + msgp.Uint32Size + 5 + msgp.BytesPrefixSize + len(z.Data)
return return
} }
// DecodeMsg implements msgp.Decodable // DecodeMsg implements msgp.Decodable
func (z *Kind) DecodeMsg(dc *msgp.Reader) (err error) { func (z *msgpRawPacket) DecodeMsg(dc *msgp.Reader) (err error) {
{ var field []byte
var zb0001 uint8 _ = field
zb0001, err = dc.ReadUint8() var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil { if err != nil {
err = msgp.WrapError(err) err = msgp.WrapError(err)
return return
} }
(*z) = Kind(zb0001) 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.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 return
} }
// EncodeMsg implements msgp.Encodable // EncodeMsg implements msgp.Encodable
func (z Kind) EncodeMsg(en *msgp.Writer) (err error) { func (z *msgpRawPacket) EncodeMsg(en *msgp.Writer) (err error) {
err = en.WriteUint8(uint8(z)) // map header, size 2
// write "id"
err = en.Append(0x82, 0xa2, 0x69, 0x64)
if err != nil { 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
} }
return return
} }
// MarshalMsg implements msgp.Marshaler // 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.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 return
} }
// UnmarshalMsg implements msgp.Unmarshaler // UnmarshalMsg implements msgp.Unmarshaler
func (z *Kind) UnmarshalMsg(bts []byte) (o []byte, err error) { func (z *msgpRawPacket) UnmarshalMsg(bts []byte) (o []byte, err error) {
{ var field []byte
var zb0001 uint8 _ = field
zb0001, bts, err = msgp.ReadUint8Bytes(bts) var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil { if err != nil {
err = msgp.WrapError(err) err = msgp.WrapError(err)
return return
} }
(*z) = Kind(zb0001) 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.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 o = bts
return return
} }
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z Kind) Msgsize() (s int) { func (z *msgpRawPacket) Msgsize() (s int) {
s = msgp.Uint8Size s = 1 + 3 + msgp.Uint32Size + 5 + msgp.BytesPrefixSize + len(z.Data)
return return
} }

View file

@ -1,4 +1,4 @@
package gotelem package skylab
// Code generated by github.com/tinylib/msgp DO NOT EDIT. // Code generated by github.com/tinylib/msgp DO NOT EDIT.
@ -9,8 +9,8 @@ import (
"github.com/tinylib/msgp/msgp" "github.com/tinylib/msgp/msgp"
) )
func TestMarshalUnmarshalCanFilter(t *testing.T) { func TestMarshalUnmarshalmsgpRawEvent(t *testing.T) {
v := CanFilter{} v := msgpRawEvent{}
bts, err := v.MarshalMsg(nil) bts, err := v.MarshalMsg(nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -32,8 +32,8 @@ func TestMarshalUnmarshalCanFilter(t *testing.T) {
} }
} }
func BenchmarkMarshalMsgCanFilter(b *testing.B) { func BenchmarkMarshalMsgmsgpRawEvent(b *testing.B) {
v := CanFilter{} v := msgpRawEvent{}
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -41,8 +41,8 @@ func BenchmarkMarshalMsgCanFilter(b *testing.B) {
} }
} }
func BenchmarkAppendMsgCanFilter(b *testing.B) { func BenchmarkAppendMsgmsgpRawEvent(b *testing.B) {
v := CanFilter{} v := msgpRawEvent{}
bts := make([]byte, 0, v.Msgsize()) bts := make([]byte, 0, v.Msgsize())
bts, _ = v.MarshalMsg(bts[0:0]) bts, _ = v.MarshalMsg(bts[0:0])
b.SetBytes(int64(len(bts))) b.SetBytes(int64(len(bts)))
@ -53,8 +53,8 @@ func BenchmarkAppendMsgCanFilter(b *testing.B) {
} }
} }
func BenchmarkUnmarshalCanFilter(b *testing.B) { func BenchmarkUnmarshalmsgpRawEvent(b *testing.B) {
v := CanFilter{} v := msgpRawEvent{}
bts, _ := v.MarshalMsg(nil) bts, _ := v.MarshalMsg(nil)
b.ReportAllocs() b.ReportAllocs()
b.SetBytes(int64(len(bts))) b.SetBytes(int64(len(bts)))
@ -67,17 +67,17 @@ func BenchmarkUnmarshalCanFilter(b *testing.B) {
} }
} }
func TestEncodeDecodeCanFilter(t *testing.T) { func TestEncodeDecodemsgpRawEvent(t *testing.T) {
v := CanFilter{} v := msgpRawEvent{}
var buf bytes.Buffer var buf bytes.Buffer
msgp.Encode(&buf, &v) msgp.Encode(&buf, &v)
m := v.Msgsize() m := v.Msgsize()
if buf.Len() > m { 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) err := msgp.Decode(&buf, &vn)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -91,8 +91,8 @@ func TestEncodeDecodeCanFilter(t *testing.T) {
} }
} }
func BenchmarkEncodeCanFilter(b *testing.B) { func BenchmarkEncodemsgpRawEvent(b *testing.B) {
v := CanFilter{} v := msgpRawEvent{}
var buf bytes.Buffer var buf bytes.Buffer
msgp.Encode(&buf, &v) msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len())) b.SetBytes(int64(buf.Len()))
@ -105,8 +105,8 @@ func BenchmarkEncodeCanFilter(b *testing.B) {
en.Flush() en.Flush()
} }
func BenchmarkDecodeCanFilter(b *testing.B) { func BenchmarkDecodemsgpRawEvent(b *testing.B) {
v := CanFilter{} v := msgpRawEvent{}
var buf bytes.Buffer var buf bytes.Buffer
msgp.Encode(&buf, &v) msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len())) b.SetBytes(int64(buf.Len()))
@ -122,8 +122,8 @@ func BenchmarkDecodeCanFilter(b *testing.B) {
} }
} }
func TestMarshalUnmarshalFrame(t *testing.T) { func TestMarshalUnmarshalmsgpRawPacket(t *testing.T) {
v := Frame{} v := msgpRawPacket{}
bts, err := v.MarshalMsg(nil) bts, err := v.MarshalMsg(nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -145,8 +145,8 @@ func TestMarshalUnmarshalFrame(t *testing.T) {
} }
} }
func BenchmarkMarshalMsgFrame(b *testing.B) { func BenchmarkMarshalMsgmsgpRawPacket(b *testing.B) {
v := Frame{} v := msgpRawPacket{}
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -154,8 +154,8 @@ func BenchmarkMarshalMsgFrame(b *testing.B) {
} }
} }
func BenchmarkAppendMsgFrame(b *testing.B) { func BenchmarkAppendMsgmsgpRawPacket(b *testing.B) {
v := Frame{} v := msgpRawPacket{}
bts := make([]byte, 0, v.Msgsize()) bts := make([]byte, 0, v.Msgsize())
bts, _ = v.MarshalMsg(bts[0:0]) bts, _ = v.MarshalMsg(bts[0:0])
b.SetBytes(int64(len(bts))) b.SetBytes(int64(len(bts)))
@ -166,8 +166,8 @@ func BenchmarkAppendMsgFrame(b *testing.B) {
} }
} }
func BenchmarkUnmarshalFrame(b *testing.B) { func BenchmarkUnmarshalmsgpRawPacket(b *testing.B) {
v := Frame{} v := msgpRawPacket{}
bts, _ := v.MarshalMsg(nil) bts, _ := v.MarshalMsg(nil)
b.ReportAllocs() b.ReportAllocs()
b.SetBytes(int64(len(bts))) b.SetBytes(int64(len(bts)))
@ -180,17 +180,17 @@ func BenchmarkUnmarshalFrame(b *testing.B) {
} }
} }
func TestEncodeDecodeFrame(t *testing.T) { func TestEncodeDecodemsgpRawPacket(t *testing.T) {
v := Frame{} v := msgpRawPacket{}
var buf bytes.Buffer var buf bytes.Buffer
msgp.Encode(&buf, &v) msgp.Encode(&buf, &v)
m := v.Msgsize() m := v.Msgsize()
if buf.Len() > m { 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) err := msgp.Decode(&buf, &vn)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -204,8 +204,8 @@ func TestEncodeDecodeFrame(t *testing.T) {
} }
} }
func BenchmarkEncodeFrame(b *testing.B) { func BenchmarkEncodemsgpRawPacket(b *testing.B) {
v := Frame{} v := msgpRawPacket{}
var buf bytes.Buffer var buf bytes.Buffer
msgp.Encode(&buf, &v) msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len())) b.SetBytes(int64(buf.Len()))
@ -218,8 +218,8 @@ func BenchmarkEncodeFrame(b *testing.B) {
en.Flush() en.Flush()
} }
func BenchmarkDecodeFrame(b *testing.B) { func BenchmarkDecodemsgpRawPacket(b *testing.B) {
v := Frame{} v := msgpRawPacket{}
var buf bytes.Buffer var buf bytes.Buffer
msgp.Encode(&buf, &v) msgp.Encode(&buf, &v)
b.SetBytes(int64(buf.Len())) b.SetBytes(int64(buf.Len()))

View file

@ -11,7 +11,7 @@ type {{$bfname}} struct {
{{- end}} {{- end}}
} }
func (p *{{$bfname}}) Marshal() byte { func (p *{{$bfname}}) MarshalByte() byte {
var b byte var b byte
{{- range $idx, $el := .Bits}} {{- range $idx, $el := .Bits}}
{{- $bitName := camelCase $el.Name true}} {{- $bitName := camelCase $el.Name true}}
@ -22,7 +22,7 @@ func (p *{{$bfname}}) Marshal() byte {
return b return b
} }
func (p *{{$bfname}}) Unmarshal(b byte) { func (p *{{$bfname}}) UnmarshalByte(b byte) {
{{- range $idx, $el := .Bits}} {{- range $idx, $el := .Bits}}
{{- $bitName := camelCase $el.Name true }} {{- $bitName := camelCase $el.Name true }}
p.{{$bitName}} = (b & (1 << {{ $idx }})) != 0 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. // If the CAN ID is unknown, it will return an error.
func FromCanFrame(id uint32, data []byte) (Packet, error) { func FromCanFrame(id uint32, data []byte) (Packet, error) {
if !idMap[id] { if !idMap[id] {
return nil, errors.New("Unknown Id") return nil, errors.New("unknown id")
} }
switch id { switch id {
{{- range $p := .Packets }} {{- range $p := .Packets }}
@ -133,34 +133,32 @@ func FromCanFrame(id uint32, data []byte) (Packet, error) {
{{- end}} {{- 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 func FromJson (id uint32, raw []byte) (Packet, error) {
jp := &JSONPacket{} if !idMap[id] {
err := json.Unmarshal(raw, jp) return nil, errors.New("unknown id")
if err != nil {
return nil, err
} }
switch jp.Id { switch id {
{{- range $p := .Packets }} {{- range $p := .Packets }}
{{- if $p.Repeat }} {{- if $p.Repeat }}
case {{ Nx (int $p.Id) $p.Repeat $p.Offset | mapf "0x%X" | strJoin ", " -}}: case {{ Nx (int $p.Id) $p.Repeat $p.Offset | mapf "0x%X" | strJoin ", " -}}:
var res = &{{camelCase $p.Name true}}{} var res = &{{camelCase $p.Name true}}{}
err := json.Unmarshal(jp.Data, res) err := json.Unmarshal(raw, res)
res.Idx = jp.Id - {{ $p.Id | printf "0x%X" }} res.Idx = id - {{ $p.Id | printf "0x%X" }}
return res, err return res, err
{{- else }} {{- else }}
case {{ $p.Id | printf "0x%X" }}: case {{ $p.Id | printf "0x%X" }}:
var res = &{{camelCase $p.Name true}}{} var res = &{{camelCase $p.Name true}}{}
err := json.Unmarshal(jp.Data, res) err := json.Unmarshal(raw, res)
return res, err return res, err
{{- end }} {{- end }}
{{- end }} {{- end }}
} }
return nil, errors.New("aaa") return nil, errors.New("failed to match id")
} }
{{range .Packets -}} {{range .Packets -}}

View file

@ -23,17 +23,14 @@ func TestMarshalUnmarshal{{$structName}}(t *testing.T) {
func TestJSON{{$structName}}(t *testing.T) { func TestJSON{{$structName}}(t *testing.T) {
v := &{{$structName}}{} v := &{{$structName}}{}
jp, err := ToJson(v)
rawData, err := json.Marshal(v)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
rawData, err := json.Marshal(jp) id, _ := v.CANId()
if err != nil { p, err := FromJson(id, rawData)
t.Fatal(err)
}
p, err := FromJson(rawData)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -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"`
}