summaryrefslogtreecommitdiff
path: root/util/pinmap/readers/csv/csv.go
blob: 562b5c638382cb2d56a912bbf7242a550760db10 (plain)
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
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package csv

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"os"
	"strings"

	"pinmap/pm"
)

// CSVReader reads the EC pin references from a comma separated
// values file.
type CSVReader struct {
}

// Name returns the name of this reader.
func (r *CSVReader) Name() string {
	return "csv"
}

// Read reads the CSV file (provided as an argument) and extracts
// the pin reference data. The first line is expected to be column
// titles that are used to identify the columns.
// columnKey identifies the column to use for the pin allocations,
// such as "A", "B" etc.
func (r *CSVReader) Read(columnKey, filepath string) (*pm.Pins, error) {
	if len(columnKey) != 1 {
		return nil, fmt.Errorf("illegal column name: '%s'", columnKey)
	}
	column := int(strings.ToLower(columnKey)[0] - 'a')
	if column < 0 || column > 'Z'-'A' {
		return nil, fmt.Errorf("illegal column name (should be 'A' - 'Z')")
	}
	f, err := os.Open(filepath)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	rdr := csv.NewReader(bufio.NewReader(f))
	data, err := rdr.ReadAll()
	if err != nil {
		return nil, err
	}
	if len(data) < 2 {
		return nil, fmt.Errorf("no data in file")
	}
	if len(data[0]) < column {
		return nil, fmt.Errorf("Column '%s' is out of range", columnKey)
	}
	// Put the CSV headers into a map.
	cmap := make(map[string]int)
	for c, s := range data[0] {
		cmap[s] = c
	}
	// Find the matching columns that are needed.
	signal, ok := cmap["Signal Name"]
	if !ok {
		return nil, fmt.Errorf("missing 'Signal Name' column")
	}
	chipKey := data[0][column]
	chip, ok := cmap[chipKey]
	if !ok {
		return nil, fmt.Errorf("missing '%s' chip column", chipKey)
	}
	ptype, ok := cmap["Type"]
	if !ok {
		return nil, fmt.Errorf("missing 'Type' column")
	}
	enum, ok := cmap["Enum"]
	if !ok {
		return nil, fmt.Errorf("missing 'Enum' column")
	}
	var pins pm.Pins
	// Read the rest of the rows.
	for i, row := range data[1:] {
		p := new(pm.Pin)
		switch row[ptype] {
		default:
			fmt.Printf("%s:%d: Unknown signal type (%s) - ignored\n", filepath, i+1, row[ptype])
			continue
		case "OTHER":
		case "PWM":
		case "PWM_INVERT":
			// Skipped
			continue
		case "ADC":
			p.PinType = pm.ADC
			pins.Adc = append(pins.Adc, p)
		case "I2C_DATA":
			// Only the clock pin is used for the config
			continue
		case "I2C_CLOCK":
			p.PinType = pm.I2C
			pins.I2c = append(pins.I2c, p)
		case "INPUT":
			p.PinType = pm.Input
			pins.Gpio = append(pins.Gpio, p)
		case "INPUT_L":
			p.PinType = pm.InputL
			pins.Gpio = append(pins.Gpio, p)
		case "INPUT_PU":
			p.PinType = pm.InputPU
			pins.Gpio = append(pins.Gpio, p)
		case "INPUT_PU_L":
			p.PinType = pm.InputPUL
			pins.Gpio = append(pins.Gpio, p)
		case "INPUT_PD":
			p.PinType = pm.InputPD
			pins.Gpio = append(pins.Gpio, p)
		case "OUTPUT":
			p.PinType = pm.Output
			pins.Gpio = append(pins.Gpio, p)
		case "OUTPUT_L":
			p.PinType = pm.OutputL
			pins.Gpio = append(pins.Gpio, p)
		case "OUTPUT_ODL":
			p.PinType = pm.OutputODL
			pins.Gpio = append(pins.Gpio, p)
		case "OUTPUT_ODR":
			p.PinType = pm.OutputOD
			pins.Gpio = append(pins.Gpio, p)
		}
		p.Signal = row[signal]
		p.Pin = row[chip]
		p.Enum = row[enum]
	}

	return &pins, nil
}