2014-10-30 08:51:47 +08:00
|
|
|
package sysfs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
2014-12-24 04:43:55 +08:00
|
|
|
"syscall"
|
2014-10-30 08:51:47 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2014-12-31 22:12:25 +08:00
|
|
|
// IN gpio direction
|
|
|
|
IN = "in"
|
|
|
|
// OUT gpio direction
|
|
|
|
OUT = "out"
|
|
|
|
// HIGH gpio level
|
|
|
|
HIGH = 1
|
|
|
|
// LOW gpio level
|
|
|
|
LOW = 0
|
|
|
|
// GPIOPATH default linux gpio path
|
2014-10-31 04:41:27 +08:00
|
|
|
GPIOPATH = "/sys/class/gpio"
|
2014-10-30 08:51:47 +08:00
|
|
|
)
|
|
|
|
|
2014-12-31 22:12:25 +08:00
|
|
|
// DigitalPin is the interface for sysfs gpio interactions
|
2014-11-04 11:02:20 +08:00
|
|
|
type DigitalPin interface {
|
2014-12-31 22:12:25 +08:00
|
|
|
// Unexport unexports the pin and releases the pin from the operating system
|
2014-11-04 11:02:20 +08:00
|
|
|
Unexport() error
|
2014-12-31 22:12:25 +08:00
|
|
|
// Export exports the pin for use by the operating system
|
2014-11-04 11:02:20 +08:00
|
|
|
Export() error
|
2014-12-31 22:12:25 +08:00
|
|
|
// Read reads the current value of the pin
|
2014-11-04 11:02:20 +08:00
|
|
|
Read() (int, error)
|
2014-12-31 22:12:25 +08:00
|
|
|
// Direction sets the direction for the pin
|
2014-11-04 11:02:20 +08:00
|
|
|
Direction(string) error
|
2014-12-31 22:12:25 +08:00
|
|
|
// Write writes to the pin
|
2014-11-04 11:02:20 +08:00
|
|
|
Write(int) error
|
|
|
|
}
|
|
|
|
|
|
|
|
type digitalPin struct {
|
|
|
|
pin string
|
|
|
|
label string
|
2014-10-30 08:51:47 +08:00
|
|
|
}
|
|
|
|
|
2014-10-31 07:22:25 +08:00
|
|
|
// NewDigitalPin returns a DigitalPin given the pin number and an optional sysfs pin label.
|
|
|
|
// If no label is supplied the default label will prepend "gpio" to the pin number,
|
|
|
|
// eg. a pin number of 10 will have a label of "gpio10"
|
2014-11-04 11:02:20 +08:00
|
|
|
func NewDigitalPin(pin int, v ...string) DigitalPin {
|
|
|
|
d := &digitalPin{pin: strconv.Itoa(pin)}
|
2014-10-31 06:26:31 +08:00
|
|
|
if len(v) > 0 {
|
|
|
|
d.label = v[0]
|
|
|
|
} else {
|
|
|
|
d.label = "gpio" + d.pin
|
|
|
|
}
|
|
|
|
|
|
|
|
return d
|
2014-10-30 08:51:47 +08:00
|
|
|
}
|
2014-10-31 04:41:27 +08:00
|
|
|
|
2014-11-04 11:02:20 +08:00
|
|
|
func (d *digitalPin) Direction(dir string) error {
|
2014-11-08 08:21:39 +08:00
|
|
|
_, err := writeFile(fmt.Sprintf("%v/%v/direction", GPIOPATH, d.label), []byte(dir))
|
2014-10-30 08:51:47 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2014-11-04 11:02:20 +08:00
|
|
|
func (d *digitalPin) Write(b int) error {
|
2014-11-08 08:21:39 +08:00
|
|
|
_, err := writeFile(fmt.Sprintf("%v/%v/value", GPIOPATH, d.label), []byte(strconv.Itoa(b)))
|
2014-10-31 04:41:27 +08:00
|
|
|
return err
|
2014-10-30 08:51:47 +08:00
|
|
|
}
|
|
|
|
|
2014-11-04 11:02:20 +08:00
|
|
|
func (d *digitalPin) Read() (n int, err error) {
|
2014-11-08 08:21:39 +08:00
|
|
|
buf, err := readFile(fmt.Sprintf("%v/%v/value", GPIOPATH, d.label))
|
2014-10-31 04:41:27 +08:00
|
|
|
if err != nil {
|
2014-11-08 08:21:39 +08:00
|
|
|
return 0, err
|
2014-10-31 04:41:27 +08:00
|
|
|
}
|
|
|
|
return strconv.Atoi(string(buf[0]))
|
2014-10-30 08:51:47 +08:00
|
|
|
}
|
|
|
|
|
2014-11-04 11:02:20 +08:00
|
|
|
func (d *digitalPin) Export() error {
|
2014-12-24 04:43:55 +08:00
|
|
|
if _, err := writeFile(GPIOPATH+"/export", []byte(d.pin)); err != nil {
|
|
|
|
// If EBUSY then the pin has already been exported
|
|
|
|
if err.(*os.PathError).Err != syscall.EBUSY {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2014-10-30 08:51:47 +08:00
|
|
|
}
|
|
|
|
|
2014-11-04 11:02:20 +08:00
|
|
|
func (d *digitalPin) Unexport() error {
|
2014-12-24 04:43:55 +08:00
|
|
|
if _, err := writeFile(GPIOPATH+"/unexport", []byte(d.pin)); err != nil {
|
|
|
|
// If EINVAL then the pin is reserved in the system and can't be unexported
|
|
|
|
if err.(*os.PathError).Err != syscall.EINVAL {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2014-10-30 08:51:47 +08:00
|
|
|
}
|
2014-10-31 04:41:27 +08:00
|
|
|
|
2014-12-24 04:43:55 +08:00
|
|
|
var writeFile = func(path string, data []byte) (i int, err error) {
|
2014-11-08 08:21:39 +08:00
|
|
|
file, err := OpenFile(path, os.O_WRONLY, 0644)
|
2014-10-31 04:41:27 +08:00
|
|
|
defer file.Close()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return file.Write(data)
|
|
|
|
}
|
2014-10-31 07:06:04 +08:00
|
|
|
|
2014-12-24 04:43:55 +08:00
|
|
|
var readFile = func(path string) ([]byte, error) {
|
2014-11-08 08:21:39 +08:00
|
|
|
file, err := OpenFile(path, os.O_RDONLY, 0644)
|
|
|
|
defer file.Close()
|
|
|
|
if err != nil {
|
|
|
|
return make([]byte, 0), err
|
|
|
|
}
|
|
|
|
|
|
|
|
buf := make([]byte, 2)
|
|
|
|
_, err = file.Read(buf)
|
|
|
|
return buf, err
|
2014-10-31 07:06:04 +08:00
|
|
|
}
|