aboutsummaryrefslogtreecommitdiffstats
path: root/sw/cal/table.go
blob: 610448a47c563afdc4d465707de3de911f575cb2 (plain) (blame)
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)
}