forked from hybridgroup/gobot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pwm_pin.go
216 lines (187 loc) · 5.29 KB
/
pwm_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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package sysfs
import (
"bytes"
"fmt"
"os"
"strconv"
"syscall"
"time"
)
// PWMPin is the interface for sysfs PWM interactions
type PWMPinner interface {
// Export exports the pin for use by the operating system
Export() error
// Unexport unexports the pin and releases the pin from the operating system
Unexport() error
// Enable enables/disables the PWM pin
Enable(bool) (err error)
// Polarity returns the polarity either normal or inverted
Polarity() (polarity string, err error)
// InvertPolarity sets the polarity to inverted if called with true
InvertPolarity(invert bool) (err error)
// Period returns the current PWM period for pin
Period() (period uint32, err error)
// SetPeriod sets the current PWM period for pin
SetPeriod(period uint32) (err error)
// DutyCycle returns the duty cycle for the pin
DutyCycle() (duty uint32, err error)
// SetDutyCycle writes the duty cycle to the pin
SetDutyCycle(duty uint32) (err error)
}
// PWMPinnerProvider is the interface that an Adaptor should implement to allow
// clients to obtain access to any PWMPin's available on that board.
type PWMPinnerProvider interface {
PWMPin(string) (PWMPinner, error)
}
type PWMPin struct {
pin string
Path string
enabled bool
write func(path string, data []byte) (i int, err error)
read func(path string) ([]byte, error)
}
// NewPwmPin returns a new pwmPin
func NewPWMPin(pin int) *PWMPin {
return &PWMPin{
pin: strconv.Itoa(pin),
enabled: false,
Path: "/sys/class/pwm/pwmchip0",
read: readPwmFile,
write: writePwmFile}
}
// Export writes pin to pwm export path
func (p *PWMPin) Export() error {
_, err := p.write(p.pwmExportPath(), []byte(p.pin))
if err != nil {
// If EBUSY then the pin has already been exported
e, ok := err.(*os.PathError)
if !ok || e.Err != syscall.EBUSY {
return err
}
}
// Pause to avoid race condition in case there is any udev rule
// that changes file permissions on newly exported PWMPin. This
// is a common circumstance when running as a non-root user.
time.Sleep(100 * time.Millisecond)
return nil
}
// Unexport writes pin to pwm unexport path
func (p *PWMPin) Unexport() (err error) {
_, err = p.write(p.pwmUnexportPath(), []byte(p.pin))
return
}
// Enable writes value to pwm enable path
func (p *PWMPin) Enable(enable bool) (err error) {
if p.enabled != enable {
p.enabled = enable
enableVal := 0
if enable {
enableVal = 1
}
_, err = p.write(p.pwmEnablePath(), []byte(fmt.Sprintf("%v", enableVal)))
}
return
}
// Polarity returns current polarity value
func (p *PWMPin) Polarity() (polarity string, err error) {
buf, err := p.read(p.pwmPolarityPath())
if err != nil {
return
}
if len(buf) == 0 {
return "", nil
}
return string(buf), nil
}
// InvertPolarity writes value to pwm polarity path
func (p *PWMPin) InvertPolarity(invert bool) (err error) {
if !p.enabled {
polarity := "normal"
if invert {
polarity = "inverted"
}
_, err = p.write(p.pwmPolarityPath(), []byte(polarity))
} else {
err = fmt.Errorf("Cannot set PWM polarity when enabled")
}
return
}
// Period reads from pwm period path and returns value in nanoseconds
func (p *PWMPin) Period() (period uint32, err error) {
buf, err := p.read(p.pwmPeriodPath())
if err != nil {
return
}
if len(buf) == 0 {
return 0, nil
}
v := bytes.TrimRight(buf, "\n")
val, e := strconv.Atoi(string(v))
return uint32(val), e
}
// SetPeriod sets pwm period in nanoseconds
func (p *PWMPin) SetPeriod(period uint32) (err error) {
_, err = p.write(p.pwmPeriodPath(), []byte(fmt.Sprintf("%v", period)))
return
}
// DutyCycle reads from pwm duty cycle path and returns value in nanoseconds
func (p *PWMPin) DutyCycle() (duty uint32, err error) {
buf, err := p.read(p.pwmDutyCyclePath())
if err != nil {
return
}
val, e := strconv.Atoi(string(buf))
return uint32(val), e
}
// SetDutyCycle writes value to pwm duty cycle path
// duty is in nanoseconds
func (p *PWMPin) SetDutyCycle(duty uint32) (err error) {
_, err = p.write(p.pwmDutyCyclePath(), []byte(fmt.Sprintf("%v", duty)))
return
}
// pwmExportPath returns export path
func (p *PWMPin) pwmExportPath() string {
return p.Path + "/export"
}
// pwmUnexportPath returns unexport path
func (p *PWMPin) pwmUnexportPath() string {
return p.Path + "/unexport"
}
// pwmDutyCyclePath returns duty_cycle path for specified pin
func (p *PWMPin) pwmDutyCyclePath() string {
return p.Path + "/pwm" + p.pin + "/duty_cycle"
}
// pwmPeriodPath returns period path for specified pin
func (p *PWMPin) pwmPeriodPath() string {
return p.Path + "/pwm" + p.pin + "/period"
}
// pwmEnablePath returns enable path for specified pin
func (p *PWMPin) pwmEnablePath() string {
return p.Path + "/pwm" + p.pin + "/enable"
}
// pwmPolarityPath returns polarity path for specified pin
func (p *PWMPin) pwmPolarityPath() string {
return p.Path + "/pwm" + p.pin + "/polarity"
}
func writePwmFile(path string, data []byte) (i int, err error) {
file, err := OpenFile(path, os.O_WRONLY, 0644)
defer file.Close()
if err != nil {
return
}
return file.Write(data)
}
func readPwmFile(path string) ([]byte, error) {
file, err := OpenFile(path, os.O_RDONLY, 0644)
defer file.Close()
if err != nil {
return make([]byte, 0), err
}
buf := make([]byte, 200)
var i int
i, err = file.Read(buf)
if i == 0 {
return []byte{}, err
}
return buf[:i], err
}