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
|
package main
import (
"flag"
"fmt"
"math"
"os"
"go.einride.tech/can/pkg/dbc"
"git.samanthony.xyz/can_gauge_interface/sw/cal/canbus"
)
type Signals struct {
tach, speed, an1, an2, an3, an4 *dbc.SignalDef
}
// Flags
var (
// DBC file
dbcFilenameFlag = "dbc"
dbcFilename = flag.String(dbcFilenameFlag, "", "DBC file")
// SocketCAN device
canDev = flag.String("can", "can0", "SocketCAN device")
// Signal names
tachSig = flag.String("tachsig", "", "tachometer signal name")
speedSig = flag.String("speedsig", "", "speedometer signal name")
an1Sig = flag.String("an1sig", "", "analog channel 1 signal name")
an2Sig = flag.String("an2sig", "", "analog channel 2 signal name")
an3Sig = flag.String("an3sig", "", "analog channel 3 signal name")
an4Sig = flag.String("an4sig", "", "analog channel 4 signal name")
// Calibration tables
tachTblFlag = "tachtbl"
speedTblFlag = "speedtbl"
an1TblFlag = "an1tbl"
an2TblFlag = "an2tbl"
an3TblFlag = "an3tbl"
an4TblFlag = "an4tbl"
tachTbl = flag.String(tachTblFlag, "", "tachometer calibration CSV file")
speedTbl = flag.String(speedTblFlag, "", "speedometer calibration CSV file")
an1Tbl = flag.String(an1TblFlag, "", "analog channel 1 calibration CSV file")
an2Tbl = flag.String(an2TblFlag, "", "analog channel 2 calibration CSV file")
an3Tbl = flag.String(an3TblFlag, "", "analog channel 3 calibration CSV file")
an4Tbl = flag.String(an4TblFlag, "", "analog channel 4 calibration CSV file")
)
func main() {
// Parse command line args
flag.Parse()
if *dbcFilename == "" {
weprintf("Missing flag: -%s\n", dbcFilenameFlag)
flag.Usage()
os.Exit(1)
}
if err := checkTablesProvided(); err != nil {
eprintf("%v\n", err)
}
sigNames := nonEmpty(*tachSig, *speedSig, *an1Sig, *an2Sig, *an3Sig, *an4Sig)
tblFilenames := nonEmpty(*tachTbl, *speedTbl, *an1Tbl, *an2Tbl, *an3Tbl, *an4Tbl)
// Open CAN connection
fmt.Println("Opening connection to", *canDev)
bus, err := canbus.Connect(*canDev)
if err != nil {
eprintf("%v\n", err)
}
defer bus.Close()
// Parse DBC file and transmit encoding of each signal
if err := sendEncodings(*dbcFilename, sigNames, bus); err != nil {
eprintf("%v\n", err)
}
// Parse tables and transmit them
if err := sendTables(tblFilenames, bus); err != nil {
eprintf("%v\n", err)
}
}
// Return a map of non-empty strings keyed by their index in the given list.
func nonEmpty(ss ...string) map[uint8]string {
if len(ss) > math.MaxUint8 {
panic(len(ss))
}
m := make(map[uint8]string)
for i := range ss {
if ss[i] != "" {
m[uint8(i)] = ss[i]
}
}
return m
}
// Check that the user provided a corresponding table for each signal they gave.
func checkTablesProvided() error {
signals := []string{*tachSig, *speedSig, *an1Sig, *an2Sig, *an3Sig, *an4Sig}
tables := []string{*tachTbl, *speedTbl, *an1Tbl, *an2Tbl, *an3Tbl, *an4Tbl}
tableFlags := []string{tachTblFlag, speedTblFlag, an1TblFlag, an2TblFlag, an3TblFlag, an4TblFlag}
for i := range signals {
if signals[i] != "" && tables[i] == "" {
// No corresponding table
return fmt.Errorf("Missing flag -%s", tableFlags[i])
}
}
return nil // all present signals have a matching table
}
// Parse DBC file and transmit encoding of each signal using Signal Control frames.
func sendEncodings(dbcFilename string, sigNames map[uint8]string, bus canbus.Bus) error {
// Parse DBC file
fmt.Println("Parsing", dbcFilename)
sigs, err := parseSignals(dbcFilename, sigNames)
if err != nil {
return err
}
// Transmit Signal Control frames
for _, sig := range sigs {
fmt.Println("Sending signal encoding", sig)
if err := sig.SendEncoding(bus); err != nil {
return err
}
fmt.Printf("Signal encoding %d OK\n", sig.index)
}
return nil
}
// Parse each table and transmit them using Table Control frames.
func sendTables(tblFilenames map[uint8]string, bus canbus.Bus) error {
for k, filename := range tblFilenames {
fmt.Printf("Parsing table %d: %s\n", k, filename)
tbl, err := parseTable(filename, k)
if err != nil {
return err
}
fmt.Printf("Sending table %d\n", k)
if err := tbl.Send(bus); err != nil {
return err
}
fmt.Printf("Table %d OK\n", k)
}
return nil
}
|