Refactor kafka to pure Go (franz-go), fix DBC stubs, update Dockerfile

This commit is contained in:
Chris Rai
2026-01-31 00:05:47 -05:00
parent fbb820d7b3
commit b5bec57dfa
776 changed files with 18945 additions and 2052 deletions

View File

@@ -0,0 +1,976 @@
package generate
import (
"bytes"
"fmt"
"go/format"
"go/types"
"path"
"strings"
"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/descriptor"
"github.com/shurcooL/go-goon"
)
type File struct {
buf bytes.Buffer
err error
}
func NewFile() *File {
f := &File{}
f.buf.Grow(1e5) // 100K
return f
}
func (f *File) Write(p []byte) (int, error) {
if f.err != nil {
return 0, f.err
}
n, err := f.buf.Write(p)
f.err = err
return n, err
}
func (f *File) P(v ...interface{}) {
for _, x := range v {
_, _ = fmt.Fprint(f, x)
}
_, _ = fmt.Fprintln(f)
}
func (f *File) Dump(v interface{}) {
_, _ = goon.Fdump(f, v)
}
func (f *File) Content() ([]byte, error) {
if f.err != nil {
return nil, fmt.Errorf("file content: %w", f.err)
}
formatted, err := format.Source(f.buf.Bytes())
if err != nil {
return nil, fmt.Errorf("file content: %s: %w", f.buf.String(), err)
}
return formatted, nil
}
func Database(h string, d *descriptor.Database) ([]byte, error) {
f := NewFile()
Package(f, d)
Imports(f)
Version(f, h, d.Version)
ListECUs(f, d)
for _, m := range d.Messages {
if m == nil {
continue
}
MessageType(f, m)
for _, s := range m.Signals {
if hasCustomType(s) {
SignalCustomType(f, m, s)
}
}
MarshalFrame(f, m)
UnmarshalFrame(f, m)
}
if hasSendType(d) { // only code-generate nodes for schemas with send types specified
for _, n := range d.Nodes {
Node(f, d, n)
}
}
Descriptors(f, d)
return f.Content()
}
func Package(f *File, d *descriptor.Database) {
packageName := strings.TrimSuffix(path.Base(d.SourceFile), path.Ext(d.SourceFile)) + "can"
f.P("// Package ", packageName, " provides primitives for encoding and decoding ", d.Name(), " CAN messages.")
f.P("//")
f.P("// Source: ", d.SourceFile)
f.P("package ", packageName)
f.P()
}
func Imports(f *File) {
f.P("import (")
f.P(`"context"`)
f.P(`"fmt"`)
f.P(`"net"`)
f.P(`"net/http"`)
f.P(`"sync"`)
f.P(`"time"`)
f.P()
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go"`)
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/socketcan"`)
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/candebug"`)
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/canrunner"`)
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/descriptor"`)
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/generated"`)
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/cantext"`)
f.P(")")
f.P()
// we could use goimports for this, but it significantly slows down code generation
f.P("// prevent unused imports")
f.P("var (")
f.P("_ = context.Background")
f.P("_ = fmt.Print")
f.P("_ = net.Dial")
f.P("_ = http.Error")
f.P("_ = sync.Mutex{}")
f.P("_ = time.Now")
f.P("_ = socketcan.Dial")
f.P("_ = candebug.ServeMessagesHTTP")
f.P("_ = canrunner.Run")
f.P(")")
f.P()
f.P("// Generated code. DO NOT EDIT.")
}
func Version(f *File, h string, v string) {
f.P()
f.P("// Hash used as versioning control for DBC")
f.P(`const Hash string = "`, h, `"`)
f.P("// Version is the version listed in the DBC")
f.P(`const Version string = "`, v, `"`)
f.P()
}
func ListECUs(f *File, d *descriptor.Database) {
f.P()
f.P("// ECUs parsed from DBC")
ecuList := "var ECUs = []string{"
i := 0
for ecu := range d.ECUs {
ecuList += fmt.Sprintf(`"%s"`, ecu)
i++
if i != len(d.ECUs) {
ecuList += ", "
}
}
ecuList += "}"
f.P(ecuList)
f.P()
}
func SignalCustomType(f *File, m *descriptor.Message, s *descriptor.Signal) {
f.P("// ", signalType(m, s), " models the ", s.Name, " signal of the ", m.Name, " message.")
f.P("type ", signalType(m, s), " ", signalPrimitiveType(s))
f.P()
// dtaylor@fiskerinc.com EDIT
// f.P("// Value descriptions for the ", s.Name, " signal of the ", m.Name, " message.")
// f.P("const (")
// for _, vd := range s.ValueDescriptions {
// switch {
// case s.Length == 1 && vd.Value == 1:
// f.P(signalType(m, s), "_", vd.Description, " ", signalType(m, s), " = true")
// case s.Length == 1 && vd.Value == 0:
// f.P(signalType(m, s), "_", vd.Description, " ", signalType(m, s), " = false")
// default:
// f.P(signalType(m, s), "_", vd.Description, " ", signalType(m, s), " = ", vd.Value)
// }
// }
// f.P(")")
// f.P()
f.P("func (v ", signalType(m, s), ") String() string {")
if s.Length == 1 {
f.P("switch bool(v) {")
for _, vd := range s.ValueDescriptions {
if vd.Value == 1 {
f.P("case true:")
} else {
f.P("case false:")
}
f.P(`return "`, vd.Description, `"`)
}
f.P("}")
f.P(`return fmt.Sprintf("`, signalType(m, s), `(%t)", v)`)
} else {
f.P("switch v {")
for _, vd := range s.ValueDescriptions {
f.P("case ", vd.Value, ":")
f.P(`return "`, vd.Description, `"`)
}
f.P("default:")
f.P(`return fmt.Sprintf("`, signalType(m, s), `(%d)", v)`)
f.P("}")
}
f.P("}")
}
func MessageType(f *File, m *descriptor.Message) {
f.P("// ", messageReaderInterface(m), " provides read access to a ", m.Name, " message.")
f.P("type ", messageReaderInterface(m), " interface {")
for _, s := range m.Signals {
if hasPhysicalRepresentation(s) {
f.P("// ", s.Name, " returns the physical value of the ", s.Name, " signal.")
f.P(s.Name, "() float64")
if len(s.ValueDescriptions) > 0 {
f.P()
f.P("// ", s.Name, " returns the raw (encoded) value of the ", s.Name, " signal.")
f.P("Raw", s.Name, "() ", signalType(m, s))
}
} else {
f.P("// ", s.Name, " returns the value of the ", s.Name, " signal.")
f.P(s.Name, "()", signalType(m, s))
}
}
f.P("}")
f.P()
f.P("// ", messageWriterInterface(m), " provides write access to a ", m.Name, " message.")
f.P("type ", messageWriterInterface(m), " interface {")
f.P("// CopyFrom copies all values from ", messageReaderInterface(m), ".")
f.P("CopyFrom(", messageReaderInterface(m), ") *", messageStruct(m))
for _, s := range m.Signals {
if hasPhysicalRepresentation(s) {
f.P("// Set", s.Name, " sets the physical value of the ", s.Name, " signal.")
f.P("Set", s.Name, "(float64) *", messageStruct(m))
if len(s.ValueDescriptions) > 0 {
f.P()
f.P("// SetRaw", s.Name, " sets the raw (encoded) value of the ", s.Name, " signal.")
f.P("SetRaw", s.Name, "(", signalType(m, s), ") *", messageStruct(m))
}
} else {
f.P("// Set", s.Name, " sets the value of the ", s.Name, " signal.")
f.P("Set", s.Name, "(", signalType(m, s), ") *", messageStruct(m))
}
}
f.P("}")
f.P()
f.P("type ", messageStruct(m), " struct {")
for _, s := range m.Signals {
f.P(signalField(s), " ", signalType(m, s))
}
f.P("}")
f.P()
f.P("func New", messageStruct(m), "() *", messageStruct(m), " {")
f.P("m := &", messageStruct(m), "{}")
f.P("m.Reset()")
f.P("return m")
f.P("}")
f.P()
f.P("func (m *", messageStruct(m), ") Reset() {")
for _, s := range m.Signals {
switch {
case s.Length == 1 && s.DefaultValue == 1:
f.P("m.", signalField(s), " = true")
case s.Length == 1:
f.P("m.", signalField(s), " = false")
default:
f.P("m.", signalField(s), " = ", s.DefaultValue)
}
}
f.P("}")
f.P()
f.P("func (m *", messageStruct(m), ") CopyFrom(o ", messageReaderInterface(m), ") *", messageStruct(m), "{")
for _, s := range m.Signals {
if hasPhysicalRepresentation(s) {
f.P("m.Set", s.Name, "(o.", s.Name, "())")
} else {
f.P("m.", signalField(s), " = o.", s.Name, "()")
}
}
f.P("return m")
f.P("}")
f.P()
f.P("// Descriptor returns the ", m.Name, " descriptor.")
f.P("func (m *", messageStruct(m), ") Descriptor() *descriptor.Message {")
f.P("return ", messageDescriptor(m), ".Message")
f.P("}")
f.P()
f.P("// String returns a compact string representation of the message.")
f.P("func(m *", messageStruct(m), ") String() string {")
f.P("return cantext.MessageString(m)")
f.P("}")
f.P()
for _, s := range m.Signals {
if !hasPhysicalRepresentation(s) {
f.P("func (m *", messageStruct(m), ") ", s.Name, "() ", signalType(m, s), " {")
f.P("return m.", signalField(s))
f.P("}")
f.P()
f.P("func (m *", messageStruct(m), ") Set", s.Name, "(v ", signalType(m, s), ") *", messageStruct(m), " {")
if s.Length == 1 {
f.P("m.", signalField(s), " = v")
} else {
f.P(
"m.", signalField(s), " = ", signalType(m, s), "(",
signalDescriptor(m, s), ".SaturatedCast", signalSuperType(s), "(",
signalPrimitiveSuperType(s), "(v)))",
)
}
f.P("return m")
f.P("}")
f.P()
continue
}
f.P("func (m *", messageStruct(m), ") ", s.Name, "() float64 {")
f.P("return ", signalDescriptor(m, s), ".ToPhysical(float64(m.", signalField(s), "))")
f.P("}")
f.P()
f.P("func (m *", messageStruct(m), ") Set", s.Name, "(v float64) *", messageStruct(m), " {")
f.P("m.", signalField(s), " = ", signalType(m, s), "(", signalDescriptor(m, s), ".FromPhysical(v))")
f.P("return m")
f.P("}")
f.P()
if len(s.ValueDescriptions) > 0 {
f.P("func (m *", messageStruct(m), ") Raw", s.Name, "() ", signalType(m, s), " {")
f.P("return m.", signalField(s))
f.P("}")
f.P()
f.P("func (m *", messageStruct(m), ") SetRaw", s.Name, "(v ", signalType(m, s), ") *", messageStruct(m), "{")
f.P(
"m.", signalField(s), " = ", signalType(m, s), "(",
signalDescriptor(m, s), ".SaturatedCast", signalSuperType(s), "(",
signalPrimitiveSuperType(s), "(v)))",
)
f.P("return m")
f.P("}")
f.P()
}
}
}
func Descriptors(f *File, d *descriptor.Database) {
f.P("// Nodes returns the ", d.Name(), " node descriptors.")
f.P("func Nodes() *NodesDescriptor {")
f.P("return nd")
f.P("}")
f.P()
f.P("// NodesDescriptor contains all ", d.Name(), " node descriptors.")
f.P("type NodesDescriptor struct{")
for _, n := range d.Nodes {
f.P(n.Name, " *descriptor.Node")
}
f.P("}")
f.P()
f.P("// Messages returns the ", d.Name(), " message descriptors.")
f.P("func Messages() *MessagesDescriptor {")
f.P("return md")
f.P("}")
f.P()
f.P("// MessagesDescriptor contains all ", d.Name(), " message descriptors.")
f.P("type MessagesDescriptor struct{")
for _, m := range d.Messages {
if m == nil {
continue
}
f.P(m.Name, " *", m.Name, "Descriptor")
}
f.P("}")
f.P()
f.P("// UnmarshalFrame unmarshals the provided ", d.Name(), " CAN frame.")
f.P("func (md *MessagesDescriptor) UnmarshalFrame(f can.Frame) (generated.Message, error) {")
f.P("switch f.ID {")
for _, m := range d.Messages {
if m == nil {
continue
}
f.P("case md.", m.Name, ".ID:")
f.P("var msg ", messageStruct(m))
f.P("if err := msg.UnmarshalFrame(f); err != nil {")
f.P(`return nil, fmt.Errorf("unmarshal `, d.Name(), ` frame: %w", err)`)
f.P("}")
f.P("return &msg, nil")
}
f.P("default:")
f.P(`return nil, fmt.Errorf("unmarshal `, d.Name(), ` frame: ID not in database: %d", f.ID)`)
f.P("}")
f.P("}")
f.P()
for _, m := range d.Messages {
if m == nil {
continue
}
f.P("type ", m.Name, "Descriptor struct{")
f.P("*descriptor.Message")
for _, s := range m.Signals {
f.P(s.Name, " *descriptor.Signal")
}
f.P("}")
f.P()
}
f.P("// Database returns the ", d.Name(), " database descriptor.")
f.P("func (md *MessagesDescriptor) Database() *descriptor.Database {")
f.P("return d")
f.P("}")
f.P()
f.P("var nd = &NodesDescriptor{")
for ni, n := range d.Nodes {
f.P(n.Name, ": d.Nodes[", ni, "],")
}
f.P("}")
f.P()
f.P("var md = &MessagesDescriptor{")
for mi, m := range d.Messages {
if m == nil {
continue
}
f.P(m.Name, ": &", m.Name, "Descriptor{")
f.P("Message: d.Messages[", mi, "],")
for si, s := range m.Signals {
f.P(s.Name, ": d.Messages[", mi, "].Signals[", si, "],")
}
f.P("},")
}
f.P("}")
f.P()
f.P("var d = ")
f.Dump(d)
f.P()
}
func MarshalFrame(f *File, m *descriptor.Message) {
f.P("// Frame returns a CAN frame representing the message.")
f.P("func (m *", messageStruct(m), ") Frame() can.Frame {")
f.P("md := ", messageDescriptor(m))
f.P("f := can.Frame{ID: md.ID, IsExtended: md.IsExtended, Length: md.Length}")
for _, s := range m.Signals {
if s.IsMultiplexed {
continue
}
f.P(
"md.", s.Name, ".Marshal", signalSuperType(s),
"(&f.Data, ", signalPrimitiveSuperType(s), "(m.", signalField(s), "))",
)
}
if mux, ok := m.MultiplexerSignal(); ok {
for _, s := range m.Signals {
if !s.IsMultiplexed {
continue
}
f.P("if m.", signalField(mux), " == ", s.MultiplexerValue, " {")
f.P(
"md.", s.Name, ".Marshal", signalSuperType(s), "(&f.Data, ", signalPrimitiveSuperType(s),
"(m.", signalField(s), "))",
)
f.P("}")
}
}
f.P("return f")
f.P("}")
f.P()
f.P("// MarshalFrame encodes the message as a CAN frame.")
f.P("func (m *", messageStruct(m), ") MarshalFrame() (can.Frame, error) {")
f.P("return m.Frame(), nil")
f.P("}")
f.P()
}
func UnmarshalFrame(f *File, m *descriptor.Message) {
f.P("// UnmarshalFrame decodes the message from a CAN frame.")
f.P("func (m *", messageStruct(m), ") UnmarshalFrame(f can.Frame) error {")
f.P("md := ", messageDescriptor(m))
// generate frame checks
id := func(isExtended bool) string {
if isExtended {
return "extended ID"
}
return "standard ID"
}
f.P("switch {")
f.P("case f.ID != md.ID:")
f.P(`return fmt.Errorf(`)
f.P(`"unmarshal `, m.Name, `: expects ID `, m.ID, ` (got %s with ID %d)", f.String(), f.ID,`)
f.P(`)`)
f.P("case f.Length != md.Length:")
f.P(`return fmt.Errorf(`)
f.P(`"unmarshal `, m.Name, `: expects length `, m.Length, ` (got %s with length %d)", f.String(), f.Length,`)
f.P(`)`)
f.P("case f.IsRemote:")
f.P(`return fmt.Errorf(`)
f.P(`"unmarshal `, m.Name, `: expects non-remote frame (got remote frame %s)", f.String(),`)
f.P(`)`)
f.P("case f.IsExtended != md.IsExtended:")
f.P(`return fmt.Errorf(`)
f.P(`"unmarshal `, m.Name, `: expects `, id(m.IsExtended), ` (got %s with `, id(!m.IsExtended), `)", f.String(),`)
f.P(`)`)
f.P("}")
if len(m.Signals) == 0 {
f.P("return nil")
f.P("}")
return
}
// generate non-multiplexed signal unmarshaling
for _, s := range m.Signals {
if s.IsMultiplexed {
continue
}
f.P("m.", signalField(s), " = ", signalType(m, s), "(md.", s.Name, ".Unmarshal", signalSuperType(s), "(f.Data))")
}
// generate multiplexed signal unmarshaling
if mux, ok := m.MultiplexerSignal(); ok {
for _, s := range m.Signals {
if !s.IsMultiplexed {
continue
}
f.P("if m.", signalField(mux), " == ", s.MultiplexerValue, " {")
f.P("m.", signalField(s), " = ", signalType(m, s), "(md.", s.Name, ".Unmarshal", signalSuperType(s), "(f.Data))")
f.P("}")
}
}
f.P("return nil")
f.P("}")
f.P()
}
func Node(f *File, d *descriptor.Database, n *descriptor.Node) {
rxMessages := collectRxMessages(d, n)
txMessages := collectTxMessages(d, n)
f.P("type ", nodeInterface(n), " interface {")
f.P("sync.Locker")
f.P("Tx() ", txGroupInterface(n))
f.P("Rx() ", rxGroupInterface(n))
f.P("Run(ctx context.Context) error")
f.P("}")
f.P()
f.P("type ", rxGroupInterface(n), " interface {")
f.P("http.Handler // for debugging")
for _, m := range rxMessages {
f.P(m.Name, "() ", rxMessageInterface(n, m))
}
f.P("}")
f.P()
f.P("type ", txGroupInterface(n), " interface {")
f.P("http.Handler // for debugging")
for _, m := range txMessages {
f.P(m.Name, "() ", txMessageInterface(n, m))
}
f.P("}")
f.P()
for _, m := range rxMessages {
f.P("type ", rxMessageInterface(n, m), " interface {")
f.P(messageReaderInterface(m))
f.P("ReceiveTime() time.Time")
f.P("SetAfterReceiveHook(h func(context.Context) error)")
f.P("}")
f.P()
}
for _, m := range txMessages {
f.P("type ", txMessageInterface(n, m), " interface {")
f.P(messageReaderInterface(m))
f.P(messageWriterInterface(m))
f.P("TransmitTime() time.Time")
f.P("Transmit(ctx context.Context) error")
f.P("SetBeforeTransmitHook(h func(context.Context) error)")
if m.SendType == descriptor.SendTypeCyclic {
f.P("// SetCyclicTransmissionEnabled enables/disables cyclic transmission.")
f.P("SetCyclicTransmissionEnabled(bool)")
f.P("// IsCyclicTransmissionEnabled returns whether cyclic transmission is enabled/disabled.")
f.P("IsCyclicTransmissionEnabled() bool")
}
f.P("}")
f.P()
}
f.P("type ", nodeStruct(n), " struct {")
f.P("sync.Mutex // protects all node state")
f.P("network string")
f.P("address string")
f.P("rx ", rxGroupStruct(n))
f.P("tx ", txGroupStruct(n))
f.P("}")
f.P()
f.P("var _ ", nodeInterface(n), " = &", nodeStruct(n), "{}")
f.P("var _ canrunner.Node = &", nodeStruct(n), "{}")
f.P()
f.P("func New", nodeInterface(n), "(network, address string) ", nodeInterface(n), " {")
f.P("n := &", nodeStruct(n), "{network: network, address: address}")
f.P("n.rx.parentMutex = &n.Mutex")
f.P("n.tx.parentMutex = &n.Mutex")
for _, m := range rxMessages {
f.P("n.rx.", messageField(m), ".init()")
f.P("n.rx.", messageField(m), ".Reset()")
}
for _, m := range txMessages {
f.P("n.tx.", messageField(m), ".init()")
f.P("n.tx.", messageField(m), ".Reset()")
}
f.P("return n")
f.P("}")
f.P()
f.P("func (n *", nodeStruct(n), ") Run(ctx context.Context) error {")
f.P("return canrunner.Run(ctx, n)")
f.P("}")
f.P()
f.P("func (n *", nodeStruct(n), ") Rx() ", rxGroupInterface(n), " {")
f.P("return &n.rx")
f.P("}")
f.P()
f.P("func (n *", nodeStruct(n), ") Tx() ", txGroupInterface(n), " {")
f.P("return &n.tx")
f.P("}")
f.P()
f.P("type ", rxGroupStruct(n), " struct {")
f.P("parentMutex *sync.Mutex")
for _, m := range rxMessages {
f.P(messageField(m), " ", rxMessageStruct(n, m))
}
f.P("}")
f.P()
f.P("var _ ", rxGroupInterface(n), " = &", rxGroupStruct(n), "{}")
f.P()
f.P("func (rx *", rxGroupStruct(n), ") ServeHTTP(w http.ResponseWriter, r *http.Request) {")
f.P("rx.parentMutex.Lock()")
f.P("defer rx.parentMutex.Unlock()")
f.P("candebug.ServeMessagesHTTP(w, r, []generated.Message{")
for _, m := range rxMessages {
f.P("&rx.", messageField(m), ",")
}
f.P("})")
f.P("}")
f.P()
for _, m := range rxMessages {
f.P("func (rx *", rxGroupStruct(n), ") ", m.Name, "() ", rxMessageInterface(n, m), " {")
f.P("return &rx.", messageField(m))
f.P("}")
f.P()
}
f.P()
f.P("type ", txGroupStruct(n), " struct {")
f.P("parentMutex *sync.Mutex")
for _, m := range txMessages {
f.P(messageField(m), " ", txMessageStruct(n, m))
}
f.P("}")
f.P()
f.P("var _ ", txGroupInterface(n), " = &", txGroupStruct(n), "{}")
f.P()
f.P("func (tx *", txGroupStruct(n), ") ServeHTTP(w http.ResponseWriter, r *http.Request) {")
f.P("tx.parentMutex.Lock()")
f.P("defer tx.parentMutex.Unlock()")
f.P("candebug.ServeMessagesHTTP(w, r, []generated.Message{")
for _, m := range txMessages {
f.P("&tx.", messageField(m), ",")
}
f.P("})")
f.P("}")
f.P()
for _, m := range txMessages {
f.P("func (tx *", txGroupStruct(n), ") ", m.Name, "() ", txMessageInterface(n, m), " {")
f.P("return &tx.", messageField(m))
f.P("}")
f.P()
}
f.P()
f.P("func (n *", nodeStruct(n), ") Descriptor() *descriptor.Node {")
f.P("return ", nodeDescriptor(n))
f.P("}")
f.P()
f.P("func (n *", nodeStruct(n), ") Connect() (net.Conn, error) {")
f.P("return socketcan.Dial(n.network, n.address)")
f.P("}")
f.P()
f.P("func (n *", nodeStruct(n), ") ReceivedMessage(id uint32) (canrunner.ReceivedMessage, bool) {")
f.P("switch id {")
for _, m := range rxMessages {
f.P("case ", m.ID, ":")
f.P("return &n.rx.", messageField(m), ", true")
}
f.P("default:")
f.P("return nil, false")
f.P("}")
f.P("}")
f.P()
f.P("func (n *", nodeStruct(n), ") TransmittedMessages() []canrunner.TransmittedMessage {")
f.P("return []canrunner.TransmittedMessage{")
for _, m := range txMessages {
f.P("&n.tx.", messageField(m), ",")
}
f.P("}")
f.P("}")
f.P()
for _, m := range rxMessages {
f.P("type ", rxMessageStruct(n, m), " struct {")
f.P(messageStruct(m))
f.P("receiveTime time.Time")
f.P("afterReceiveHook func(context.Context) error")
f.P("}")
f.P()
f.P("func (m *", rxMessageStruct(n, m), ") init() {")
f.P("m.afterReceiveHook = func(context.Context) error { return nil }")
f.P("}")
f.P()
f.P("func (m *", rxMessageStruct(n, m), ") SetAfterReceiveHook(h func(context.Context) error) {")
f.P("m.afterReceiveHook = h")
f.P("}")
f.P()
f.P("func (m *", rxMessageStruct(n, m), ") AfterReceiveHook() func(context.Context) error {")
f.P("return m.afterReceiveHook")
f.P("}")
f.P()
f.P("func (m *", rxMessageStruct(n, m), ") ReceiveTime() time.Time {")
f.P("return m.receiveTime")
f.P("}")
f.P()
f.P("func (m *", rxMessageStruct(n, m), ") SetReceiveTime(t time.Time) {")
f.P("m.receiveTime = t")
f.P("}")
f.P()
f.P("var _ canrunner.ReceivedMessage = &", rxMessageStruct(n, m), "{}")
f.P()
}
for _, m := range txMessages {
f.P("type ", txMessageStruct(n, m), " struct {")
f.P(messageStruct(m))
f.P("transmitTime time.Time")
f.P("beforeTransmitHook func(context.Context) error")
f.P("isCyclicEnabled bool")
f.P("wakeUpChan chan struct{}")
f.P("transmitEventChan chan struct{}")
f.P("}")
f.P()
f.P("var _ ", txMessageInterface(n, m), " = &", txMessageStruct(n, m), "{}")
f.P("var _ canrunner.TransmittedMessage = &", txMessageStruct(n, m), "{}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") init() {")
f.P("m.beforeTransmitHook = func(context.Context) error { return nil }")
f.P("m.wakeUpChan = make(chan struct{}, 1)")
f.P("m.transmitEventChan = make(chan struct{})")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") SetBeforeTransmitHook(h func(context.Context) error) {")
f.P("m.beforeTransmitHook = h")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") BeforeTransmitHook() func(context.Context) error {")
f.P("return m.beforeTransmitHook")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") TransmitTime() time.Time {")
f.P("return m.transmitTime")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") SetTransmitTime(t time.Time) {")
f.P("m.transmitTime = t")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") IsCyclicTransmissionEnabled() bool {")
f.P("return m.isCyclicEnabled")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") SetCyclicTransmissionEnabled(b bool) {")
f.P("m.isCyclicEnabled = b")
f.P("select {")
f.P("case m.wakeUpChan <-struct{}{}:")
f.P("default:")
f.P("}")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") WakeUpChan() <-chan struct{} {")
f.P("return m.wakeUpChan")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") Transmit(ctx context.Context) error {")
f.P("select {")
f.P("case m.transmitEventChan <- struct{}{}:")
f.P("return nil")
f.P("case <-ctx.Done():")
f.P(`return fmt.Errorf("event-triggered transmit of `, m.Name, `: %w", ctx.Err())`)
f.P("}")
f.P("}")
f.P()
f.P("func (m *", txMessageStruct(n, m), ") TransmitEventChan() <-chan struct{} {")
f.P("return m.transmitEventChan")
f.P("}")
f.P()
f.P("var _ canrunner.TransmittedMessage = &", txMessageStruct(n, m), "{}")
f.P()
}
}
func txGroupInterface(n *descriptor.Node) string {
return n.Name + "_Tx"
}
func txGroupStruct(n *descriptor.Node) string {
return "xxx_" + n.Name + "_Tx"
}
func rxGroupInterface(n *descriptor.Node) string {
return n.Name + "_Rx"
}
func rxGroupStruct(n *descriptor.Node) string {
return "xxx_" + n.Name + "_Rx"
}
func rxMessageInterface(n *descriptor.Node, m *descriptor.Message) string {
return n.Name + "_Rx_" + m.Name
}
func rxMessageStruct(n *descriptor.Node, m *descriptor.Message) string {
return "xxx_" + n.Name + "_Rx_" + m.Name
}
func txMessageInterface(n *descriptor.Node, m *descriptor.Message) string {
return n.Name + "_Tx_" + m.Name
}
func txMessageStruct(n *descriptor.Node, m *descriptor.Message) string {
return "xxx_" + n.Name + "_Tx_" + m.Name
}
func collectTxMessages(d *descriptor.Database, n *descriptor.Node) []*descriptor.Message {
tx := make([]*descriptor.Message, 0, len(d.Messages))
for _, m := range d.Messages {
if m == nil {
continue
}
if m.SenderNode == n.Name && m.SendType != descriptor.SendTypeNone {
tx = append(tx, m)
}
}
return tx
}
func collectRxMessages(d *descriptor.Database, n *descriptor.Node) []*descriptor.Message {
rx := make([]*descriptor.Message, 0, len(d.Messages))
Loop:
for _, m := range d.Messages {
if m == nil {
continue
}
for _, s := range m.Signals {
for _, node := range s.ReceiverNodes {
if node != n.Name {
continue
}
rx = append(rx, m)
continue Loop
}
}
}
return rx
}
func hasPhysicalRepresentation(s *descriptor.Signal) bool {
hasScale := s.Scale != 0 && s.Scale != 1
hasOffset := s.Offset != 0
hasRange := s.Min != 0 || s.Max != 0
var hasConstrainedRange bool
if s.IsSigned {
hasConstrainedRange = s.Min > float64(s.MinSigned()) || s.Max < float64(s.MaxSigned())
} else {
hasConstrainedRange = s.Min > 0 || s.Max < float64(s.MaxUnsigned())
}
return hasScale || hasOffset || hasRange && hasConstrainedRange
}
func hasCustomType(s *descriptor.Signal) bool {
return len(s.ValueDescriptions) > 0
}
func hasSendType(d *descriptor.Database) bool {
for _, m := range d.Messages {
if m == nil {
continue
}
if m.SendType != descriptor.SendTypeNone {
return true
}
}
return false
}
func signalType(m *descriptor.Message, s *descriptor.Signal) string {
if hasCustomType(s) {
return m.Name + "_" + s.Name
}
return signalPrimitiveType(s).String()
}
func signalPrimitiveType(s *descriptor.Signal) types.Type {
var t types.BasicKind
switch {
case s.Length == 1:
t = types.Bool
case s.Length <= 8 && s.IsSigned:
t = types.Int8
case s.Length <= 8:
t = types.Uint8
case s.Length <= 16 && s.IsSigned:
t = types.Int16
case s.Length <= 16:
t = types.Uint16
case s.Length <= 32 && s.IsSigned:
t = types.Int32
case s.Length <= 32:
t = types.Uint32
case s.Length <= 64 && s.IsSigned:
t = types.Int64
default:
t = types.Uint64
}
return types.Typ[t]
}
func signalPrimitiveSuperType(s *descriptor.Signal) types.Type {
var t types.BasicKind
switch {
case s.Length == 1:
t = types.Bool
case s.IsSigned:
t = types.Int64
default:
t = types.Uint64
}
return types.Typ[t]
}
func signalSuperType(s *descriptor.Signal) string {
switch {
case s.Length == 1:
return "Bool"
case s.IsSigned:
return "Signed"
default:
return "Unsigned"
}
}
func nodeInterface(n *descriptor.Node) string {
return n.Name
}
func nodeStruct(n *descriptor.Node) string {
return "xxx_" + n.Name
}
func messageStruct(m *descriptor.Message) string {
return m.Name
}
func messageReaderInterface(m *descriptor.Message) string {
return m.Name + "Reader"
}
func messageWriterInterface(m *descriptor.Message) string {
return m.Name + "Writer"
}
func messageField(m *descriptor.Message) string {
return "xxx_" + m.Name
}
func signalField(s *descriptor.Signal) string {
return "xxx_" + s.Name
}
func nodeDescriptor(n *descriptor.Node) string {
return "Nodes()." + n.Name
}
func messageDescriptor(m *descriptor.Message) string {
return "Messages()." + m.Name
}
func signalDescriptor(m *descriptor.Message, s *descriptor.Signal) string {
return messageDescriptor(m) + "." + s.Name
}