-
Notifications
You must be signed in to change notification settings - Fork 1
/
chip.go
144 lines (122 loc) · 3.24 KB
/
chip.go
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
// SPDX-FileCopyrightText: 2023 Kent Gibson <warthog618@gmail.com>
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
package gpiosim
import (
"fmt"
"path"
"github.com/pkg/errors"
)
// Chip provides the interface to a simulated gpiochip.
//
// Lines are identified by offset into the chip, with offsets
// being in the range 0..Config().NumLines-1.
type Chip struct {
// The path to the bank in configfs
configfsPath string
// The path to the chip in /dev
devPath string
// The name of the gpiochip in /dev and sysfs.
chipName string
// The name of the device in sysfs.
devName string
// The path to the chip in /sys/device/platform.
sysfsPath string
// The configuration for this chip
cfg Bank
}
// ChipName returns the name of the gpiochip.
//
// e.g. gpiochip0
func (c *Chip) ChipName() string {
return c.chipName
}
// Config returns the configuration used for the Chip.
func (c *Chip) Config() Bank {
return c.cfg
}
// DevPath returns the path to the gpiochip device.
//
// e.g. "/dev/gpiochip0"
//
// This the path that should be opened to access the gpiochip via the uAPI.
func (c *Chip) DevPath() string {
return c.devPath
}
// Level returns the level the line is being pulled to.
//
// If the line is requested as an output then this is the level userspace is
// driving it to, and otherwise there is little point calling this method -
// you probably should be calling Pull instead.
func (c *Chip) Level(offset int) (int, error) {
v, err := c.attr(offset, "value")
if err == nil {
if v == "0" {
return LevelInactive, nil
}
if v == "1" {
return LevelActive, nil
}
err = errors.Errorf("unexpected level value: %s", v)
}
return LevelInactive, err
}
const (
// Line is inactive.
LevelInactive int = iota
// Line is active.
LevelActive
)
// Pull returns the current the pull of the given line.
func (c *Chip) Pull(offset int) (int, error) {
v, err := c.attr(offset, "pull")
if err == nil {
if v == "pull-down" {
return LevelInactive, nil
}
if v == "pull-up" {
return LevelActive, nil
}
err = errors.Errorf("unexpected pull value: %s", v)
}
return LevelInactive, err
}
// Pulldown sets the pull of the given line to pull-down.
func (c *Chip) Pulldown(offset int) error {
return c.SetPull(offset, LevelInactive)
}
// Pullup sets the pull of the given line to pull-up.
func (c *Chip) Pullup(offset int) error {
return c.SetPull(offset, LevelActive)
}
// SetPull sets the pull of the given line.
func (c *Chip) SetPull(offset int, level int) error {
l := "pull-down"
if level == LevelActive {
l = "pull-up"
}
return c.setAttr(offset, "pull", l)
}
// Toggle flips the pull of the given line.
//
// If it was pull-up it becomes pull-down, and vice versa.
func (c *Chip) Toggle(offset int) error {
p, err := c.Pull(offset)
if err != nil {
return err
}
if p == 0 {
p = 1
} else {
p = 0
}
return c.SetPull(offset, p)
}
// attr reads the given line attribute from sysfs
func (c *Chip) attr(offset int, name string) (string, error) {
return readAttr(path.Join(c.sysfsPath, fmt.Sprintf("sim_gpio%d", offset)), name)
}
// setAttr writes the given line attribute to sysfs
func (c *Chip) setAttr(offset int, name, value string) error {
return writeAttr(path.Join(c.sysfsPath, fmt.Sprintf("sim_gpio%d", offset)), name, value)
}