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 }