mirror of
https://github.com/kidoman/embd
synced 2024-12-22 21:00:05 +01:00
gpio library for rpi
This commit is contained in:
parent
283e8eb140
commit
b7096cfe6c
41
gpio/data.go
Normal file
41
gpio/data.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package gpio
|
||||||
|
|
||||||
|
var rev1Pins = pinMap{
|
||||||
|
&pinDesc{0, []string{"P1_3", "GPIO_0", "SDA", "I2C0_SDA"}, normal | i2c},
|
||||||
|
&pinDesc{1, []string{"P1_5", "GPIO_1", "SCL", "I2C0_SCL"}, normal | i2c},
|
||||||
|
&pinDesc{4, []string{"P1_7", "GPIO_4", "GPCLK0"}, normal},
|
||||||
|
&pinDesc{14, []string{"P1_8", "GPIO_14", "TXD", "UART0_TXD"}, normal | uart},
|
||||||
|
&pinDesc{15, []string{"P1_10", "GPIO_15", "RXD", "UART0_RXD"}, normal | uart},
|
||||||
|
&pinDesc{17, []string{"P1_11", "GPIO_17"}, normal},
|
||||||
|
&pinDesc{18, []string{"P1_12", "GPIO_18", "PCM_CLK"}, normal},
|
||||||
|
&pinDesc{21, []string{"P1_13", "GPIO_21"}, normal},
|
||||||
|
&pinDesc{22, []string{"P1_15", "GPIO_22"}, normal},
|
||||||
|
&pinDesc{23, []string{"P1_16", "GPIO_23"}, normal},
|
||||||
|
&pinDesc{24, []string{"P1_18", "GPIO_24"}, normal},
|
||||||
|
&pinDesc{10, []string{"P1_19", "GPIO_10", "MOSI"}, normal | spi},
|
||||||
|
&pinDesc{9, []string{"P1_21", "GPIO_9", "MISO"}, normal | spi},
|
||||||
|
&pinDesc{25, []string{"P1_22", "GPIO_25"}, normal},
|
||||||
|
&pinDesc{11, []string{"P1_23", "GPIO_11", "SCLK"}, normal | spi},
|
||||||
|
&pinDesc{8, []string{"P1_24", "GPIO_8", "CE0"}, normal | spi},
|
||||||
|
&pinDesc{7, []string{"P1_26", "GPIO_7", "CE1"}, normal | spi},
|
||||||
|
}
|
||||||
|
|
||||||
|
var rev2Pins = pinMap{
|
||||||
|
&pinDesc{2, []string{"P1_3", "GPIO_2", "SDA", "I2C1_SDA"}, normal | i2c},
|
||||||
|
&pinDesc{3, []string{"P1_5", "GPIO_3", "SCL", "I2C1_SCL"}, normal | i2c},
|
||||||
|
&pinDesc{4, []string{"P1_7", "GPIO_4", "GPCLK0"}, normal},
|
||||||
|
&pinDesc{14, []string{"P1_8", "GPIO_14", "TXD", "UART0_TXD"}, normal | uart},
|
||||||
|
&pinDesc{15, []string{"P1_10", "GPIO_15", "RXD", "UART0_RXD"}, normal | uart},
|
||||||
|
&pinDesc{17, []string{"P1_11", "GPIO_17"}, normal},
|
||||||
|
&pinDesc{18, []string{"P1_12", "GPIO_18", "PCM_CLK"}, normal},
|
||||||
|
&pinDesc{27, []string{"P1_13", "GPIO_27"}, normal},
|
||||||
|
&pinDesc{22, []string{"P1_15", "GPIO_22"}, normal},
|
||||||
|
&pinDesc{23, []string{"P1_16", "GPIO_23"}, normal},
|
||||||
|
&pinDesc{24, []string{"P1_18", "GPIO_24"}, normal},
|
||||||
|
&pinDesc{10, []string{"P1_19", "GPIO_10", "MOSI", "SPI0_MOSI"}, normal | spi},
|
||||||
|
&pinDesc{9, []string{"P1_21", "GPIO_9", "MISO", "SPI0_MISO"}, normal | spi},
|
||||||
|
&pinDesc{25, []string{"P1_22", "GPIO_25"}, normal},
|
||||||
|
&pinDesc{11, []string{"P1_23", "GPIO_11", "SCLK", "SPI0_SCLK"}, normal | spi},
|
||||||
|
&pinDesc{8, []string{"P1_24", "GPIO_8", "CE0", "SPI0_CE0_N"}, normal | spi},
|
||||||
|
&pinDesc{7, []string{"P1_26", "GPIO_7", "CE1", "SPI0_CE1_N"}, normal | spi},
|
||||||
|
}
|
226
gpio/gpio.go
Normal file
226
gpio/gpio.go
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
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()
|
||||||
|
}
|
149
gpio/pin.go
Normal file
149
gpio/pin.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package gpio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pin struct {
|
||||||
|
n int
|
||||||
|
|
||||||
|
dir *os.File
|
||||||
|
val *os.File
|
||||||
|
activeLow *os.File
|
||||||
|
edge *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPin(n int) (p *pin, err error) {
|
||||||
|
p = &pin{n: n}
|
||||||
|
err = p.init()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) init() (err error) {
|
||||||
|
if p.dir, err = p.directionFile(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.val, err = p.valueFile(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.activeLow, err = p.activeLowFile(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.edge, err = p.edgeFile(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) basePath() string {
|
||||||
|
return fmt.Sprintf("/sys/class/gpio/gpio%v", p.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) openFile(path string) (*os.File, error) {
|
||||||
|
return os.OpenFile(path, os.O_RDWR, os.ModeExclusive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) directionPath() string {
|
||||||
|
return path.Join(p.basePath(), "direction")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) directionFile() (*os.File, error) {
|
||||||
|
return p.openFile(p.directionPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) valuePath() string {
|
||||||
|
return path.Join(p.basePath(), "value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) valueFile() (*os.File, error) {
|
||||||
|
return p.openFile(p.valuePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) activeLowPath() string {
|
||||||
|
return path.Join(p.basePath(), "active_low")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) activeLowFile() (*os.File, error) {
|
||||||
|
return p.openFile(p.activeLowPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) edgePath() string {
|
||||||
|
return path.Join(p.basePath(), "edge")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) edgeFile() (*os.File, error) {
|
||||||
|
return p.openFile(p.edgePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) Mode(dir Direction) (err error) {
|
||||||
|
str := "in"
|
||||||
|
if dir == Output {
|
||||||
|
str = "out"
|
||||||
|
}
|
||||||
|
_, err = p.dir.WriteString(str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) Input() error {
|
||||||
|
return p.Mode(Input)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) Output() error {
|
||||||
|
return p.Mode(Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) Read() (s State, err error) {
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
if _, err = p.val.Read(buf); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s = Low
|
||||||
|
if buf[0] == '1' {
|
||||||
|
s = High
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) Write(s State) (err error) {
|
||||||
|
str := "0"
|
||||||
|
if s == High {
|
||||||
|
str = "1"
|
||||||
|
}
|
||||||
|
_, err = p.val.WriteString(str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) Low() error {
|
||||||
|
return p.Write(Low)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) High() error {
|
||||||
|
return p.Write(High)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) SetActiveLow(b bool) (err error) {
|
||||||
|
str := "0"
|
||||||
|
if b {
|
||||||
|
str = "1"
|
||||||
|
}
|
||||||
|
_, err = p.activeLow.WriteString(str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) ActiveLow() error {
|
||||||
|
return p.SetActiveLow(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) ActiveHigh() error {
|
||||||
|
return p.SetActiveLow(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pin) Close() {
|
||||||
|
p.dir.Close()
|
||||||
|
p.val.Close()
|
||||||
|
p.activeLow.Close()
|
||||||
|
p.edge.Close()
|
||||||
|
}
|
7
gpio/pindesc.go
Normal file
7
gpio/pindesc.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gpio
|
||||||
|
|
||||||
|
type pinDesc struct {
|
||||||
|
n int
|
||||||
|
ids []string
|
||||||
|
caps int
|
||||||
|
}
|
24
gpio/pinmap.go
Normal file
24
gpio/pinmap.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package gpio
|
||||||
|
|
||||||
|
type pinMap []*pinDesc
|
||||||
|
|
||||||
|
func (m pinMap) lookup(k interface{}) (*pinDesc, bool) {
|
||||||
|
switch key := k.(type) {
|
||||||
|
case int:
|
||||||
|
for i := range m {
|
||||||
|
if m[i].n == key {
|
||||||
|
return m[i], true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
for i := range m {
|
||||||
|
for j := range m[i].ids {
|
||||||
|
if m[i].ids[j] == key {
|
||||||
|
return m[i], true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
33
samples/gpio.go
Normal file
33
samples/gpio.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kidoman/embd/gpio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
io := gpio.New()
|
||||||
|
defer io.Close()
|
||||||
|
|
||||||
|
pin, err := io.Pin("MOSI")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := pin.Output(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := pin.ActiveLow(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := pin.Low(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
if err := pin.Input(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user