1
0
mirror of https://github.com/kidoman/embd synced 2024-12-22 12:50:19 +01:00
embd/digitalpin.go
Kunal Powar a6e3902eb0 gpio: fix a bug which prevented digital pins reads from working correctly
when reading from the value file, it is important to seek back to the front
so that we get the fresh values from the kernel driver for every new read
2014-04-05 01:28:15 +05:30

187 lines
3.2 KiB
Go

// Digital IO support.
// This driver requires kernel version 3.8+ and should work uniformly
// across all supported devices.
package embd
import (
"errors"
"fmt"
"os"
"path"
"strconv"
)
type digitalPin struct {
n int
dir *os.File
val *os.File
activeLow *os.File
edge *os.File
initialized bool
}
func newDigitalPin(n int) DigitalPin {
return &digitalPin{n: n}
}
func (p *digitalPin) N() int {
return p.n
}
func (p *digitalPin) init() error {
if p.initialized {
return nil
}
var err error
if err = p.export(); err != nil {
return err
}
if p.dir, err = p.directionFile(); err != nil {
return err
}
if p.val, err = p.valueFile(); err != nil {
return err
}
if p.activeLow, err = p.activeLowFile(); err != nil {
return err
}
p.initialized = true
return nil
}
func (p *digitalPin) export() error {
exporter, err := os.OpenFile("/sys/class/gpio/export", os.O_WRONLY, os.ModeExclusive)
if err != nil {
return err
}
defer exporter.Close()
_, err = exporter.WriteString(strconv.Itoa(p.n))
return err
}
func (p *digitalPin) unexport() error {
unexporter, err := os.OpenFile("/sys/class/gpio/unexport", os.O_WRONLY, os.ModeExclusive)
if err != nil {
return err
}
defer unexporter.Close()
_, err = unexporter.WriteString(strconv.Itoa(p.n))
return err
}
func (p *digitalPin) basePath() string {
return fmt.Sprintf("/sys/class/gpio/gpio%v", p.n)
}
func (p *digitalPin) openFile(path string) (*os.File, error) {
return os.OpenFile(path, os.O_RDWR, os.ModeExclusive)
}
func (p *digitalPin) directionFile() (*os.File, error) {
return p.openFile(path.Join(p.basePath(), "direction"))
}
func (p *digitalPin) valueFile() (*os.File, error) {
return p.openFile(path.Join(p.basePath(), "value"))
}
func (p *digitalPin) activeLowFile() (*os.File, error) {
return p.openFile(path.Join(p.basePath(), "active_low"))
}
func (p *digitalPin) SetDirection(dir Direction) error {
if err := p.init(); err != nil {
return err
}
str := "in"
if dir == Out {
str = "out"
}
_, err := p.dir.WriteString(str)
return err
}
func (p *digitalPin) Read() (int, error) {
if err := p.init(); err != nil {
return 0, err
}
buf := make([]byte, 1)
if _, err := p.val.Read(buf); err != nil {
return 0, err
}
p.val.Seek(0, 0)
var val int
if buf[0] == '1' {
val = 1
}
return val, nil
}
func (p *digitalPin) Write(val int) error {
if err := p.init(); err != nil {
return err
}
str := "0"
if val == High {
str = "1"
}
_, err := p.val.WriteString(str)
return err
}
func (p *digitalPin) ActiveLow(b bool) error {
if err := p.init(); err != nil {
return err
}
str := "0"
if b {
str = "1"
}
_, err := p.activeLow.WriteString(str)
return err
}
func (p *digitalPin) PullUp() error {
return errors.New("gpio: not implemented")
}
func (p *digitalPin) PullDown() error {
return errors.New("gpio: not implemented")
}
func (p *digitalPin) Close() error {
if !p.initialized {
return nil
}
if err := p.dir.Close(); err != nil {
return err
}
if err := p.val.Close(); err != nil {
return err
}
if err := p.activeLow.Close(); err != nil {
return err
}
if err := p.edge.Close(); err != nil {
return err
}
if err := p.unexport(); err != nil {
return err
}
p.initialized = false
return nil
}