mirror of https://github.com/kidoman/embd
227 lines
3.5 KiB
Go
227 lines
3.5 KiB
Go
|
package gpio
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"sync"
|
||
|
|
||
|
"github.com/golang/glog"
|
||
|
)
|
||
|
|
||
|
type Direction int
|
||
|
type State int
|
||
|
type Pull int
|
||
|
|
||
|
const (
|
||
|
Input Direction = iota
|
||
|
Output
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
Low State = iota
|
||
|
High
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
PullOff Pull = iota
|
||
|
PullDown
|
||
|
PullUp
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
normal = 1 << iota
|
||
|
i2c
|
||
|
spi
|
||
|
uart
|
||
|
)
|
||
|
|
||
|
type gpio struct {
|
||
|
exporter, unexporter *os.File
|
||
|
|
||
|
initialized bool
|
||
|
|
||
|
pinMap pinMap
|
||
|
initializedPins map[int]*pin
|
||
|
}
|
||
|
|
||
|
var instance *gpio
|
||
|
var instanceLock sync.Mutex
|
||
|
|
||
|
var Default *gpio
|
||
|
|
||
|
func New() *gpio {
|
||
|
instanceLock.Lock()
|
||
|
defer instanceLock.Unlock()
|
||
|
|
||
|
if instance == nil {
|
||
|
instance = &gpio{
|
||
|
pinMap: rev2Pins,
|
||
|
initializedPins: map[int]*pin{},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return instance
|
||
|
}
|
||
|
|
||
|
func (io *gpio) init() (err error) {
|
||
|
if io.initialized {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if io.exporter, err = os.OpenFile("/sys/class/gpio/export", os.O_WRONLY, os.ModeExclusive); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if io.unexporter, err = os.OpenFile("/sys/class/gpio/unexport", os.O_WRONLY, os.ModeExclusive); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
io.initialized = true
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (io *gpio) lookupKey(key interface{}) (*pinDesc, bool) {
|
||
|
return io.pinMap.lookup(key)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) export(n int) (err error) {
|
||
|
_, err = io.exporter.WriteString(strconv.Itoa(n))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (io *gpio) unexport(n int) (err error) {
|
||
|
_, err = io.unexporter.WriteString(strconv.Itoa(n))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (io *gpio) pin(key interface{}) (pin *pin, err error) {
|
||
|
pd, found := io.lookupKey(key)
|
||
|
if !found {
|
||
|
err = fmt.Errorf("gpio: could not find pin matching %q", key)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
n := pd.n
|
||
|
|
||
|
var ok bool
|
||
|
if pin, ok = io.initializedPins[n]; ok {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if pd.caps&normal == 0 {
|
||
|
err = fmt.Errorf("gpio: sorry, pin %q cannot be used for GPIO", key)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if pd.caps != normal {
|
||
|
glog.Infof("gpio: pin %q is not a dedicated GPIO pin. please refer to the system reference manual for more details", key)
|
||
|
}
|
||
|
|
||
|
if err = io.export(n); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if pin, err = NewPin(n); err != nil {
|
||
|
io.unexport(n)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
io.initializedPins[n] = pin
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (io *gpio) Pin(key interface{}) (pin *pin, err error) {
|
||
|
if err = io.init(); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
return io.pin(key)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) Mode(key interface{}, dir Direction) (err error) {
|
||
|
if err = io.init(); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var pin *pin
|
||
|
if pin, err = io.pin(key); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
return pin.Mode(dir)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) Input(key interface{}) error {
|
||
|
return io.Mode(key, Input)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) Output(key interface{}) error {
|
||
|
return io.Mode(key, Output)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) Read(key interface{}) (state State, err error) {
|
||
|
if err = io.init(); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var pin *pin
|
||
|
if pin, err = io.pin(key); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
return pin.Read()
|
||
|
}
|
||
|
|
||
|
func (io *gpio) Write(key interface{}, state State) (err error) {
|
||
|
if err = io.init(); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var pin *pin
|
||
|
if pin, err = io.pin(key); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
return pin.Write(state)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) Low(key interface{}) error {
|
||
|
return io.Write(key, Low)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) High(key interface{}) error {
|
||
|
return io.Write(key, High)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) SetActiveLow(key interface{}, b bool) (err error) {
|
||
|
if err = io.init(); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var pin *pin
|
||
|
if pin, err = io.pin(key); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
return pin.SetActiveLow(b)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) ActiveLow(key interface{}) error {
|
||
|
return io.SetActiveLow(key, true)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) ActiveHigh(key interface{}) error {
|
||
|
return io.SetActiveLow(key, false)
|
||
|
}
|
||
|
|
||
|
func (io *gpio) Close() {
|
||
|
for n := range io.initializedPins {
|
||
|
io.unexport(n)
|
||
|
}
|
||
|
|
||
|
io.exporter.Close()
|
||
|
io.unexporter.Close()
|
||
|
}
|