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
|
package main
import (
"cmp"
"context"
bin "encoding/binary"
"fmt"
"slices"
"time"
"go.einride.tech/can"
"git.samanthony.xyz/can_gauge_interface/sw/cal/canbus"
)
const (
tblCtrlId uint32 = 0x1272000
maxTabRows = 32
)
type Table struct {
sigIndex uint8
rows []Row
}
type Row struct {
key int32
val uint16
}
func (t *Table) Insert(key int32, val uint16) error {
if len(t.rows) >= maxTabRows {
return fmt.Errorf("too many rows")
}
i, ok := slices.BinarySearchFunc(t.rows, key, cmpRowKey)
if ok {
return ErrDupKey{key}
}
t.rows = slices.Insert(t.rows, i, Row{key, val})
return nil
}
func cmpRowKey(row Row, key int32) int {
return cmp.Compare(row.key, key)
}
// Transmit a table in Table Control frames so the Interface can store it in its EEPROM.
func (tbl Table) Send(bus canbus.Bus) error {
// Send populated rows
var i int
for i = 0; i < len(tbl.rows); i++ {
if err := sendRow(tbl.sigIndex, uint8(i), tbl.rows[i], bus); err != nil {
return err
}
time.Sleep(eepromWriteDelay)
}
// Fill rest of table with last row
lastRow := tbl.rows[len(tbl.rows)-1]
for ; i < maxTabRows; i++ {
if err := sendRow(tbl.sigIndex, uint8(i), lastRow, bus); err != nil {
return err
}
time.Sleep(eepromWriteDelay)
}
return nil
}
// Transmit a Table Control frame containing one row of a table.
func sendRow(sigIndex, rowIndex uint8, row Row, bus canbus.Bus) error {
// Serialize DATA FIELD
var data [8]byte
if _, err := bin.Encode(data[0:4], bin.BigEndian, row.key); err != nil {
return err
}
if _, err := bin.Encode(data[4:6], bin.BigEndian, row.val); err != nil {
return err
}
// Construct ID and send frame
frame := can.Frame{
ID: uint32(tblCtrlId) | uint32((sigIndex<<5)&0xE0) | uint32(rowIndex&0x1F),
Length: 6,
Data: data,
IsExtended: true,
}
ctx, _ := context.WithTimeout(context.Background(), timeout)
return bus.Send(ctx, frame)
}
|