-
Notifications
You must be signed in to change notification settings - Fork 0
/
canid_builder.go
195 lines (160 loc) · 5.42 KB
/
canid_builder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package acmelib
import (
"fmt"
"strings"
)
var defaulCANIDBuilder = NewCANIDBuilder("default CAN-ID builder").UseNodeID(0, 4).UseMessageID(4, 7).UseCAN2A()
// CANID is the CAN-ID of a [Message] within a [Bus].
// Every message should have a different CAN-ID.
type CANID uint32
// CANIDBuilderOpKind is the kind of an operation
// perfomed by the [CANIDBuilder].
type CANIDBuilderOpKind int
const (
// CANIDBuilderOpKindMessagePriority represents an operation
// that involves the message priority.
CANIDBuilderOpKindMessagePriority CANIDBuilderOpKind = iota
// CANIDBuilderOpKindMessageID represents an operation
// that involves the message id.
CANIDBuilderOpKindMessageID
// CANIDBuilderOpKindNodeID represents an operation
// that involves the node id.
CANIDBuilderOpKindNodeID
// CANIDBuilderOpKindBitMask represents a bit masking operation.
CANIDBuilderOpKindBitMask
)
func (bok CANIDBuilderOpKind) String() string {
switch bok {
case CANIDBuilderOpKindMessagePriority:
return "message-priority"
case CANIDBuilderOpKindMessageID:
return "message-id"
case CANIDBuilderOpKindNodeID:
return "node-id"
case CANIDBuilderOpKindBitMask:
return "bit-mask"
default:
return "unknown"
}
}
// CANIDBuilderOp is an operation performed by the [CANIDBuilder].
type CANIDBuilderOp struct {
kind CANIDBuilderOpKind
from int
len int
}
func newCANIDBuilderOp(kind CANIDBuilderOpKind, from, len int) *CANIDBuilderOp {
return &CANIDBuilderOp{
kind: kind,
from: from,
len: len,
}
}
func (bo *CANIDBuilderOp) stringify(b *strings.Builder, tabs int) {
tabStr := getTabString(tabs)
b.WriteString(fmt.Sprintf("%skind: %s\n", tabStr, bo.kind))
b.WriteString(fmt.Sprintf("%sfrom: %d; len: %d\n", tabStr, bo.from, bo.len))
}
// Kind returns the kind of the operation.
func (bo *CANIDBuilderOp) Kind() CANIDBuilderOpKind {
return bo.kind
}
// From returns the index of the first bit on which the operation is performed.
func (bo *CANIDBuilderOp) From() int {
return bo.from
}
// Len returns the number of bits on which the operation is performed.
func (bo *CANIDBuilderOp) Len() int {
return bo.len
}
// CANIDBuilder is a builder used to describe how to generate
// the CAN-ID of the messages within a [Bus].
type CANIDBuilder struct {
*entity
*withRefs[*Bus]
operations []*CANIDBuilderOp
}
func newCANIDBuilderFromEntity(ent *entity) *CANIDBuilder {
return &CANIDBuilder{
entity: ent,
withRefs: newWithRefs[*Bus](),
operations: []*CANIDBuilderOp{},
}
}
// NewCANIDBuilder creates a new [CANIDBuilder] with the given name.
func NewCANIDBuilder(name string) *CANIDBuilder {
return newCANIDBuilderFromEntity(newEntity(name, EntityKindCANIDBuilder))
}
func (b *CANIDBuilder) stringify(builder *strings.Builder, tabs int) {
b.entity.stringify(builder, tabs)
tabStr := getTabString(tabs)
builder.WriteString(fmt.Sprintf("%soperations:\n", tabStr))
for _, op := range b.operations {
op.stringify(builder, tabs+1)
}
refCount := b.ReferenceCount()
if refCount > 0 {
builder.WriteString(fmt.Sprintf("%sreference_count: %d\n", tabStr, refCount))
}
}
func (b *CANIDBuilder) String() string {
builder := new(strings.Builder)
b.stringify(builder, 0)
return builder.String()
}
// Operations returns the operations performed by the [CANIDBuilder].
func (b *CANIDBuilder) Operations() []*CANIDBuilderOp {
return b.operations
}
// Calculate returns the CAN-ID calculated by applying the operations.
func (b *CANIDBuilder) Calculate(messagePriority MessagePriority, messageID MessageID, nodeID NodeID) CANID {
canID := uint32(0)
for _, op := range b.operations {
if op.kind == CANIDBuilderOpKindBitMask {
mask := uint32(0xFFFFFFFF) >> uint32(32-op.len)
canID &= (mask << uint32(op.from))
continue
}
tmpVal := uint32(0)
switch op.kind {
case CANIDBuilderOpKindMessagePriority:
tmpVal = uint32(messagePriority)
case CANIDBuilderOpKindMessageID:
tmpVal = uint32(messageID)
case CANIDBuilderOpKindNodeID:
tmpVal = uint32(nodeID)
}
mask := uint32(0xFFFFFFFF) >> uint32(32-op.len)
tmpVal &= mask
tmpVal = tmpVal << uint32(op.from)
canID |= tmpVal
}
return CANID(canID)
}
// UseMessagePriority adds an operation that involves the message priority from the given index.
// The length of the operation is fixed (2 bits).
func (b *CANIDBuilder) UseMessagePriority(from int) *CANIDBuilder {
b.operations = append(b.operations, newCANIDBuilderOp(CANIDBuilderOpKindMessagePriority, from, 2))
return b
}
// UseMessageID adds an operation that involves the message id from the given index and length.
func (b *CANIDBuilder) UseMessageID(from, len int) *CANIDBuilder {
b.operations = append(b.operations, newCANIDBuilderOp(CANIDBuilderOpKindMessageID, from, len))
return b
}
// UseNodeID adds an operation that involves the node id from the given index and length.
func (b *CANIDBuilder) UseNodeID(from, len int) *CANIDBuilder {
b.operations = append(b.operations, newCANIDBuilderOp(CANIDBuilderOpKindNodeID, from, len))
return b
}
// UseCAN2A adds a bit mask from 0 with a length of 11,
// which makes the calculated CAN-ID conformed to the CAN 2.0A.
func (b *CANIDBuilder) UseCAN2A() *CANIDBuilder {
b.operations = append(b.operations, newCANIDBuilderOp(CANIDBuilderOpKindBitMask, 0, 11))
return b
}
// UseBitMask adds a bit mask operation from the given index and length.
func (b *CANIDBuilder) UseBitMask(from, len int) *CANIDBuilder {
b.operations = append(b.operations, newCANIDBuilderOp(CANIDBuilderOpKindBitMask, from, len))
return b
}