-
Notifications
You must be signed in to change notification settings - Fork 15
/
pin.go
158 lines (144 loc) · 2.96 KB
/
pin.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package rpi
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
// Indicate whether the pin is used for input or output.
type Direction int
const (
IN = iota // pin is used for input
OUT // pin is used for output
)
// Indicate the current state of the pin.
type Value int
const (
LOW = iota // pin is low (off)
HIGH // pin is high (on)
)
// Determine if a specific pin is exported.
func isPinExported(number int) (bool, error) {
_, err := os.Stat(fmt.Sprintf("/sys/class/gpio/gpio%d", number))
if err != nil {
if !os.IsNotExist(err) {
return false, err
}
return false, nil
}
return true, nil
}
// Export or unexport a specific pin.
func setPinExport(number int, export bool) error {
var filename string
if export {
filename = "/sys/class/gpio/export"
} else {
filename = "/sys/class/gpio/unexport"
}
f, err := os.OpenFile(filename, os.O_WRONLY, 0)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write([]byte(fmt.Sprintf("%d\n", number)))
if err != nil {
return err
}
return nil
}
// Set the direction of a pin.
func setPinDirection(number int, direction Direction) error {
filename := fmt.Sprintf("/sys/class/gpio/gpio%d/direction", number)
f, err := os.OpenFile(filename, os.O_WRONLY, 0)
if err != nil {
return err
}
defer f.Close()
var data []byte
switch direction {
case IN:
data = []byte("in\n")
case OUT:
data = []byte("out\n")
}
_, err = f.Write(data)
return err
}
// An individual GPIO pin.
type Pin struct {
number int
value *os.File
}
// Prepare a pin for input or output.
func OpenPin(number int, direction Direction) (*Pin, error) {
e, err := isPinExported(number)
if err != nil {
return nil, err
}
if !e {
if err := setPinExport(number, true); err != nil {
return nil, err
}
}
if err := setPinDirection(number, direction); err != nil {
return nil, err
}
var flag int
switch direction {
case IN:
flag = os.O_RDONLY
case OUT:
flag = os.O_WRONLY
}
f, err := os.OpenFile(fmt.Sprintf("/sys/class/gpio/gpio%d/value", number), flag, 0)
if err != nil {
return nil, err
}
return &Pin{
number: number,
value: f,
}, nil
}
// Read the current value of the pin.
func (p *Pin) Read() (Value, error) {
// seek to beginning of file in case we've read it before
if _, err := p.value.Seek(0, 0); err != nil {
return LOW, err
}
d, err := ioutil.ReadAll(p.value)
if err != nil {
return LOW, err
}
value := strings.TrimSpace(string(d))
switch value {
case "0":
return LOW, nil
case "1":
return HIGH, nil
default:
return 0, fmt.Errorf("unrecognized value '%s'", value)
}
}
// Set the current value of the pin.
func (p *Pin) Write(value Value) error {
var data []byte
switch value {
case LOW:
data = []byte("0\n")
case HIGH:
data = []byte("1\n")
}
_, err := p.value.Write(data)
return err
}
// Close the pin.
func (p *Pin) Close() error {
if err := p.value.Close(); err != nil {
return err
}
if err := setPinExport(p.number, false); err != nil {
return err
}
return nil
}