aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2025-11-07 18:15:14 -0500
committerSam Anthony <sam@samanthony.xyz>2025-11-07 18:15:14 -0500
commit688972df9daa1f80d24feff5c056ab3a66c4eee9 (patch)
tree057f1a8379cc11e747d88ee409b1db6d598f2cd6
parent29da72a76d5e043a181f66e8758c4d511c3ef814 (diff)
downloadcan-gauge-interface-688972df9daa1f80d24feff5c056ab3a66c4eee9.zip
cal: parse csv tables
-rw-r--r--sw/cal/csv.go55
-rw-r--r--sw/cal/main.go54
2 files changed, 101 insertions, 8 deletions
diff --git a/sw/cal/csv.go b/sw/cal/csv.go
new file mode 100644
index 0000000..bb5cd01
--- /dev/null
+++ b/sw/cal/csv.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "os"
+ "fmt"
+ "io"
+ "strconv"
+ "encoding/csv"
+)
+
+func parseTable(filename string) (map[int32]uint16, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ eprintf("%v\n", err)
+ }
+ defer f.Close()
+
+ tbl := make(map[int32]uint16)
+ rdr := csv.NewReader(f)
+ for {
+ err := parseRow(rdr, tbl)
+ if err == io.EOF {
+ return tbl, nil
+ } else if err != nil {
+ return nil, fmt.Errorf("%s:%v", filename, err)
+ }
+ }
+}
+
+func parseRow(rdr *csv.Reader, tbl map[int32]uint16) error {
+ row, err := rdr.Read()
+ if err != nil {
+ return err
+ }
+ if len(row) != 2 {
+ line, _ := rdr.FieldPos(0)
+ return fmt.Errorf("%d: malformed row", line)
+ }
+ key, err := strconv.ParseInt(row[0], 10, 32)
+ if err != nil {
+ line, col := rdr.FieldPos(0)
+ return fmt.Errorf("%d:%d: %v", line, col, err)
+ }
+ val, err := strconv.ParseUint(row[1], 10, 16)
+ if err != nil {
+ line, col := rdr.FieldPos(1)
+ return fmt.Errorf("%d:%d: %v", line, col, err)
+ }
+ if _, ok := tbl[int32(key)]; ok {
+ line, col := rdr.FieldPos(0)
+ return fmt.Errorf("%d: %d: duplicate key %d", line, col, key)
+ }
+ tbl[int32(key)] = uint16(val)
+ return nil
+}
diff --git a/sw/cal/main.go b/sw/cal/main.go
index 3758a07..a6e4b1d 100644
--- a/sw/cal/main.go
+++ b/sw/cal/main.go
@@ -35,7 +35,18 @@ var (
an4Sig = flag.String(an4SigFlag, "", "analog channel 4 signal name")
// Calibration tables
- // TODO
+ 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() {
@@ -46,23 +57,50 @@ func main() {
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)
// Parse signals in DBC file
+ fmt.Println("Parsing", *dbcFilename)
sigDefs, err := parseSignals(*dbcFilename, sigNames)
if err != nil {
- eprintf("Error parsing %s: %v\n", *dbcFilename, err)
+ eprintf("%v\n", err)
+ }
+
+ // Parse calibration tables
+ for _, filename := range tblFilenames {
+ fmt.Println("Parsing", filename)
+ tbl, err := parseTable(filename)
+ if err != nil {
+ eprintf("%v\n", err)
+ }
}
fmt.Println(sigDefs)
}
-func nonEmpty(ss ...string) []string {
- r := make([]string, 0, len(ss))
- for _, s := range ss {
- if s != "" {
- r = append(r, s)
+func nonEmpty(ss ...string) map[int]string {
+ m := make(map[int]string)
+ for i := range ss {
+ if ss[i] != "" {
+ m[i] = ss[i]
+ }
+ }
+ return m
+}
+
+// Check that a calibration table was provided for each given signal.
+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] == "" {
+ return fmt.Errorf("Missing flag -%s", tableFlags[i])
}
}
- return r
+ return nil
}