github.com/blueinnovationsgroup/can-go@v0.0.0-20230518195432-d0567cda0028/internal/generate/compile.go (about) 1 package generate 2 3 import ( 4 "fmt" 5 "sort" 6 "time" 7 8 "github.com/blueinnovationsgroup/can-go/pkg/dbc" 9 "github.com/blueinnovationsgroup/can-go/pkg/descriptor" 10 ) 11 12 type CompileResult struct { 13 Database *descriptor.Database 14 Warnings []error 15 } 16 17 func Compile(sourceFile, packageName string, data []byte) (result *CompileResult, err error) { 18 p := dbc.NewParser(sourceFile, data) 19 if err := p.Parse(); err != nil { 20 return nil, fmt.Errorf("failed to parse DBC source file: %w", err) 21 } 22 defs := p.Defs() 23 c := &compiler{ 24 db: &descriptor.Database{SourceFile: sourceFile, PackageName: packageName}, 25 defs: defs, 26 } 27 c.collectDescriptors() 28 c.addMetadata() 29 c.sortDescriptors() 30 return &CompileResult{Database: c.db, Warnings: c.warnings}, nil 31 } 32 33 type compileError struct { 34 def dbc.Def 35 reason string 36 } 37 38 func (e *compileError) Error() string { 39 return fmt.Sprintf("failed to compile: %v (%v)", e.reason, e.def) 40 } 41 42 type compiler struct { 43 db *descriptor.Database 44 defs []dbc.Def 45 warnings []error 46 } 47 48 func (c *compiler) addWarning(warning error) { 49 c.warnings = append(c.warnings, warning) 50 } 51 52 func (c *compiler) collectDescriptors() { 53 for _, def := range c.defs { 54 switch def := def.(type) { 55 case *dbc.VersionDef: 56 c.db.Version = def.Version 57 case *dbc.MessageDef: 58 if def.MessageID == dbc.IndependentSignalsMessageID { 59 continue // don't compile 60 } 61 message := &descriptor.Message{ 62 Name: string(def.Name), 63 ID: def.MessageID.ToCAN(), 64 IsExtended: def.MessageID.IsExtended(), 65 Length: uint8(def.Size), 66 SenderNode: string(def.Transmitter), 67 } 68 for _, signalDef := range def.Signals { 69 signal := &descriptor.Signal{ 70 Name: string(signalDef.Name), 71 IsBigEndian: signalDef.IsBigEndian, 72 IsSigned: signalDef.IsSigned, 73 IsMultiplexer: signalDef.IsMultiplexerSwitch, 74 IsMultiplexed: signalDef.IsMultiplexed, 75 MultiplexerValue: uint(signalDef.MultiplexerSwitch), 76 Start: uint8(signalDef.StartBit), 77 Length: uint8(signalDef.Size), 78 Scale: signalDef.Factor, 79 Offset: signalDef.Offset, 80 Min: signalDef.Minimum, 81 Max: signalDef.Maximum, 82 Unit: signalDef.Unit, 83 } 84 for _, receiver := range signalDef.Receivers { 85 signal.ReceiverNodes = append(signal.ReceiverNodes, string(receiver)) 86 } 87 message.Signals = append(message.Signals, signal) 88 } 89 c.db.Messages = append(c.db.Messages, message) 90 case *dbc.NodesDef: 91 for _, node := range def.NodeNames { 92 c.db.Nodes = append(c.db.Nodes, &descriptor.Node{Name: string(node)}) 93 } 94 } 95 } 96 } 97 98 func (c *compiler) addMetadata() { 99 for _, def := range c.defs { 100 switch def := def.(type) { 101 case *dbc.CommentDef: 102 switch def.ObjectType { 103 case dbc.ObjectTypeMessage: 104 if def.MessageID == dbc.IndependentSignalsMessageID { 105 continue // don't compile 106 } 107 message, ok := c.db.Message(def.MessageID.ToCAN()) 108 if !ok { 109 c.addWarning(&compileError{def: def, reason: "no declared message"}) 110 continue 111 } 112 message.Description = def.Comment 113 case dbc.ObjectTypeSignal: 114 if def.MessageID == dbc.IndependentSignalsMessageID { 115 continue // don't compile 116 } 117 signal, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName)) 118 if !ok { 119 c.addWarning(&compileError{def: def, reason: "no declared signal"}) 120 continue 121 } 122 signal.Description = def.Comment 123 case dbc.ObjectTypeNetworkNode: 124 node, ok := c.db.Node(string(def.NodeName)) 125 if !ok { 126 c.addWarning(&compileError{def: def, reason: "no declared node"}) 127 continue 128 } 129 node.Description = def.Comment 130 } 131 case *dbc.ValueDescriptionsDef: 132 if def.MessageID == dbc.IndependentSignalsMessageID { 133 continue // don't compile 134 } 135 if def.ObjectType != dbc.ObjectTypeSignal { 136 continue // don't compile 137 } 138 signal, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName)) 139 if !ok { 140 c.addWarning(&compileError{def: def, reason: "no declared signal"}) 141 continue 142 } 143 for _, valueDescription := range def.ValueDescriptions { 144 signal.ValueDescriptions = append(signal.ValueDescriptions, &descriptor.ValueDescription{ 145 Description: valueDescription.Description, 146 Value: int64(valueDescription.Value), 147 }) 148 } 149 case *dbc.AttributeValueForObjectDef: 150 switch def.ObjectType { 151 case dbc.ObjectTypeMessage: 152 msg, ok := c.db.Message(def.MessageID.ToCAN()) 153 if !ok { 154 c.addWarning(&compileError{def: def, reason: "no declared message"}) 155 continue 156 } 157 switch def.AttributeName { 158 case "GenMsgSendType": 159 if err := msg.SendType.UnmarshalString(def.StringValue); err != nil { 160 c.addWarning(&compileError{def: def, reason: err.Error()}) 161 continue 162 } 163 case "GenMsgCycleTime": 164 msg.CycleTime = time.Duration(def.IntValue) * time.Millisecond 165 case "GenMsgDelayTime": 166 msg.DelayTime = time.Duration(def.IntValue) * time.Millisecond 167 } 168 case dbc.ObjectTypeSignal: 169 sig, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName)) 170 if !ok { 171 c.addWarning(&compileError{def: def, reason: "no declared signal"}) 172 } 173 if def.AttributeName == "GenSigStartValue" { 174 sig.DefaultValue = int(def.IntValue) 175 } 176 } 177 } 178 } 179 } 180 181 func (c *compiler) sortDescriptors() { 182 // Sort nodes by name 183 sort.Slice(c.db.Nodes, func(i, j int) bool { 184 return c.db.Nodes[i].Name < c.db.Nodes[j].Name 185 }) 186 // Sort messages by ID 187 sort.Slice(c.db.Messages, func(i, j int) bool { 188 return c.db.Messages[i].ID < c.db.Messages[j].ID 189 }) 190 for _, m := range c.db.Messages { 191 m := m 192 // Sort signals by start (and multiplexer value) 193 sort.Slice(m.Signals, func(j, k int) bool { 194 if m.Signals[j].MultiplexerValue < m.Signals[k].MultiplexerValue { 195 return true 196 } 197 return m.Signals[j].Start < m.Signals[k].Start 198 }) 199 // Sort value descriptions by value 200 for _, s := range m.Signals { 201 s := s 202 sort.Slice(s.ValueDescriptions, func(k, l int) bool { 203 return s.ValueDescriptions[k].Value < s.ValueDescriptions[l].Value 204 }) 205 } 206 } 207 }