mirror of
https://github.com/kidoman/embd
synced 2024-12-21 12:20:05 +01:00
bring in the idea of a hardware abstraction layer
This commit is contained in:
parent
b4de382833
commit
b5e2d0acc7
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.floo*
|
||||
.vagrant/
|
||||
Vagrantfile
|
2
doc.go
2
doc.go
@ -26,4 +26,4 @@ Find out the heading from the LSM303 magnetometer:
|
||||
...
|
||||
heading, err := lsm303.Heading()
|
||||
*/
|
||||
package rpi
|
||||
package embd
|
||||
|
41
gpio/data.go
41
gpio/data.go
@ -1,41 +0,0 @@
|
||||
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", "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},
|
||||
}
|
||||
|
||||
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},
|
||||
}
|
221
gpio/gpio.go
221
gpio/gpio.go
@ -1,226 +1,29 @@
|
||||
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
|
||||
In Direction = iota
|
||||
Out
|
||||
)
|
||||
|
||||
const (
|
||||
Low State = iota
|
||||
Low int = iota
|
||||
High
|
||||
)
|
||||
|
||||
const (
|
||||
PullOff Pull = iota
|
||||
PullDown
|
||||
PullUp
|
||||
)
|
||||
type DigitalPin interface {
|
||||
Write(val int) error
|
||||
Read() (int, error)
|
||||
|
||||
const (
|
||||
normal = 1 << iota
|
||||
i2c
|
||||
spi
|
||||
uart
|
||||
)
|
||||
SetDir(dir Direction) error
|
||||
ActiveLow(b bool) error
|
||||
|
||||
type gpio struct {
|
||||
exporter, unexporter *os.File
|
||||
|
||||
initialized bool
|
||||
|
||||
pinMap pinMap
|
||||
initializedPins map[int]*pin
|
||||
Close() error
|
||||
}
|
||||
|
||||
var instance *gpio
|
||||
var instanceLock sync.Mutex
|
||||
type GPIO interface {
|
||||
DigitalPin(key interface{}) (DigitalPin, error)
|
||||
|
||||
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()
|
||||
Close() error
|
||||
}
|
||||
|
149
gpio/pin.go
149
gpio/pin.go
@ -1,149 +0,0 @@
|
||||
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()
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package gpio
|
||||
|
||||
type pinDesc struct {
|
||||
n int
|
||||
ids []string
|
||||
caps int
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
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
|
||||
}
|
35
hal.go
Normal file
35
hal.go
Normal file
@ -0,0 +1,35 @@
|
||||
package embd
|
||||
|
||||
import (
|
||||
"github.com/kidoman/embd/gpio"
|
||||
"github.com/kidoman/embd/host"
|
||||
"github.com/kidoman/embd/i2c"
|
||||
)
|
||||
|
||||
const (
|
||||
In = gpio.In
|
||||
Out = gpio.Out
|
||||
)
|
||||
|
||||
const (
|
||||
Low = gpio.Low
|
||||
High = gpio.High
|
||||
)
|
||||
|
||||
func NewGPIO() (gpio.GPIO, error) {
|
||||
desc, err := host.Describe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return desc.GPIO(), nil
|
||||
}
|
||||
|
||||
func NewI2C() (i2c.I2C, error) {
|
||||
desc, err := host.Describe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return desc.I2C(), nil
|
||||
}
|
28
host/describe.go
Normal file
28
host/describe.go
Normal file
@ -0,0 +1,28 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/kidoman/embd/gpio"
|
||||
"github.com/kidoman/embd/host/rpi"
|
||||
"github.com/kidoman/embd/i2c"
|
||||
)
|
||||
|
||||
type Descriptor interface {
|
||||
GPIO() gpio.GPIO
|
||||
I2C() i2c.I2C
|
||||
}
|
||||
|
||||
func Describe() (Descriptor, error) {
|
||||
host, rev, err := Detect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch host {
|
||||
case RPi:
|
||||
return rpi.Descriptor(rev), nil
|
||||
default:
|
||||
return nil, errors.New("host: invalid host")
|
||||
}
|
||||
}
|
78
host/detect.go
Normal file
78
host/detect.go
Normal file
@ -0,0 +1,78 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Host int
|
||||
|
||||
const (
|
||||
Null Host = iota
|
||||
RPi
|
||||
BBB
|
||||
)
|
||||
|
||||
func execOutput(name string, arg ...string) (output string, err error) {
|
||||
var out []byte
|
||||
if out, err = exec.Command(name, arg...).Output(); err != nil {
|
||||
return
|
||||
}
|
||||
output = string(out)
|
||||
return
|
||||
}
|
||||
|
||||
func nodeName() (string, error) {
|
||||
return execOutput("uname", "-n")
|
||||
}
|
||||
|
||||
func kernelVersion() (major, minor, patch int, err error) {
|
||||
output, err := execOutput("uname", "-r")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.Split(output, ".")
|
||||
|
||||
if major, err = strconv.Atoi(parts[0]); err != nil {
|
||||
return
|
||||
}
|
||||
if minor, err = strconv.Atoi(parts[1]); err != nil {
|
||||
return
|
||||
}
|
||||
if patch, err = strconv.Atoi(parts[2]); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func Detect() (host Host, rev int, err error) {
|
||||
major, minor, patch, err := kernelVersion()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if major < 3 || (major == 3 && minor < 8) {
|
||||
err = fmt.Errorf("embd: linux kernel versions lower than 3.8 are not supported. you have %v.%v.%v", major, minor, patch)
|
||||
return
|
||||
}
|
||||
|
||||
node, err := nodeName()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch node {
|
||||
case "raspberrypi":
|
||||
host = RPi
|
||||
case "beaglebone":
|
||||
host = BBB
|
||||
default:
|
||||
err = fmt.Errorf("embd: your host %q is not supported at this moment. please request support at https://github.com/kidoman/embd/issues", node)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
114
host/generic/linux/gpio/digitalpin.go
Normal file
114
host/generic/linux/gpio/digitalpin.go
Normal file
@ -0,0 +1,114 @@
|
||||
package gpio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/kidoman/embd/gpio"
|
||||
)
|
||||
|
||||
type digitalPin struct {
|
||||
n int
|
||||
|
||||
dir *os.File
|
||||
val *os.File
|
||||
activeLow *os.File
|
||||
edge *os.File
|
||||
}
|
||||
|
||||
func newDigitalPin(n int) (p *digitalPin, err error) {
|
||||
p = &digitalPin{n: n}
|
||||
err = p.init()
|
||||
return
|
||||
}
|
||||
|
||||
func (p *digitalPin) 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
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
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) SetDir(dir gpio.Direction) (err error) {
|
||||
str := "in"
|
||||
if dir == gpio.Out {
|
||||
str = "out"
|
||||
}
|
||||
_, err = p.dir.WriteString(str)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *digitalPin) Read() (val int, err error) {
|
||||
buf := make([]byte, 1)
|
||||
if _, err = p.val.Read(buf); err != nil {
|
||||
return
|
||||
}
|
||||
val = 0
|
||||
if buf[0] == '1' {
|
||||
val = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *digitalPin) Write(val int) (err error) {
|
||||
str := "0"
|
||||
if val == gpio.High {
|
||||
str = "1"
|
||||
}
|
||||
_, err = p.val.WriteString(str)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *digitalPin) ActiveLow(b bool) (err error) {
|
||||
str := "0"
|
||||
if b {
|
||||
str = "1"
|
||||
}
|
||||
_, err = p.activeLow.WriteString(str)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *digitalPin) Close() error {
|
||||
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
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
149
host/generic/linux/gpio/gpio.go
Normal file
149
host/generic/linux/gpio/gpio.go
Normal file
@ -0,0 +1,149 @@
|
||||
package gpio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/kidoman/embd/gpio"
|
||||
)
|
||||
|
||||
const (
|
||||
Normal int = 1 << iota
|
||||
I2C
|
||||
UART
|
||||
SPI
|
||||
)
|
||||
|
||||
type PinDesc struct {
|
||||
N int
|
||||
IDs []string
|
||||
Caps int
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type GPIO struct {
|
||||
exporter, unexporter *os.File
|
||||
|
||||
initialized bool
|
||||
|
||||
pinMap PinMap
|
||||
initializedPins map[int]*digitalPin
|
||||
}
|
||||
|
||||
func New(pinMap PinMap) *GPIO {
|
||||
return &GPIO{
|
||||
pinMap: pinMap,
|
||||
initializedPins: map[int]*digitalPin{},
|
||||
}
|
||||
}
|
||||
|
||||
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) digitalPin(key interface{}) (p *digitalPin, 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 p, 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 p, err = newDigitalPin(n); err != nil {
|
||||
io.unexport(n)
|
||||
return
|
||||
}
|
||||
|
||||
io.initializedPins[n] = p
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (io *GPIO) DigitalPin(key interface{}) (gpio.DigitalPin, error) {
|
||||
if err := io.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return io.digitalPin(key)
|
||||
}
|
||||
|
||||
func (io *GPIO) Close() error {
|
||||
for n := range io.initializedPins {
|
||||
io.unexport(n)
|
||||
}
|
||||
|
||||
io.exporter.Close()
|
||||
io.unexporter.Close()
|
||||
|
||||
return nil
|
||||
}
|
278
host/generic/linux/i2c/bus.go
Normal file
278
host/generic/linux/i2c/bus.go
Normal file
@ -0,0 +1,278 @@
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
delay = 20
|
||||
|
||||
slaveCmd = 0x0703 // Cmd to set slave address
|
||||
rdrwCmd = 0x0707 // Cmd to read/write data together
|
||||
|
||||
rd = 0x0001
|
||||
)
|
||||
|
||||
type i2c_msg struct {
|
||||
addr uint16
|
||||
flags uint16
|
||||
len uint16
|
||||
buf uintptr
|
||||
}
|
||||
|
||||
type i2c_rdwr_ioctl_data struct {
|
||||
msgs uintptr
|
||||
nmsg uint32
|
||||
}
|
||||
|
||||
type bus struct {
|
||||
l byte
|
||||
file *os.File
|
||||
addr byte
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func newBus(l byte) (*bus, error) {
|
||||
b := &bus{l: l}
|
||||
|
||||
var err error
|
||||
if b.file, err = os.OpenFile(fmt.Sprintf("/dev/i2c-%v", b.l), os.O_RDWR, os.ModeExclusive); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (b *bus) Close() error {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
return b.file.Close()
|
||||
}
|
||||
|
||||
func (b *bus) setAddress(addr byte) (err error) {
|
||||
if addr != b.addr {
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), slaveCmd, uintptr(addr)); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
b.addr = addr
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) ReadByte(addr byte) (value byte, err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bytes := make([]byte, 1)
|
||||
n, err := b.file.Read(bytes)
|
||||
|
||||
if n != 1 {
|
||||
err = fmt.Errorf("i2c: Unexpected number (%v) of bytes read", n)
|
||||
}
|
||||
|
||||
value = bytes[0]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteByte(addr, value byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
n, err := b.file.Write([]byte{value})
|
||||
|
||||
if n != 1 {
|
||||
err = fmt.Errorf("i2c: Unexpected number (%v) of bytes written in WriteByte", n)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteBytes(addr byte, value []byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range value {
|
||||
n, err := b.file.Write([]byte{value[i]})
|
||||
|
||||
if n != 1 {
|
||||
return fmt.Errorf("i2c: Unexpected number (%v) of bytes written in WriteBytes", n)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time.Sleep(delay * time.Millisecond)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *bus) ReadFromReg(addr, reg byte, value []byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&value))
|
||||
|
||||
var messages [2]i2c_msg
|
||||
messages[0].addr = uint16(addr)
|
||||
messages[0].flags = 0
|
||||
messages[0].len = 1
|
||||
messages[0].buf = uintptr(unsafe.Pointer(®))
|
||||
|
||||
messages[1].addr = uint16(addr)
|
||||
messages[1].flags = rd
|
||||
messages[1].len = uint16(len(value))
|
||||
messages[1].buf = uintptr(unsafe.Pointer(hdrp.Data))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&messages))
|
||||
packets.nmsg = 2
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
return syscall.Errno(errno)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *bus) ReadByteFromReg(addr, reg byte) (value byte, err error) {
|
||||
buf := make([]byte, 1)
|
||||
if err = b.ReadFromReg(addr, reg, buf); err != nil {
|
||||
return
|
||||
}
|
||||
value = buf[0]
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) ReadWordFromReg(addr, reg byte) (value uint16, err error) {
|
||||
buf := make([]byte, 2)
|
||||
if err = b.ReadFromReg(addr, reg, buf); err != nil {
|
||||
return
|
||||
}
|
||||
value = uint16((uint16(buf[0]) << 8) | uint16(buf[1]))
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteToReg(addr, reg byte, value []byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
outbuf := append([]byte{reg}, value...)
|
||||
|
||||
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&outbuf))
|
||||
|
||||
var message i2c_msg
|
||||
message.addr = uint16(addr)
|
||||
message.flags = 0
|
||||
message.len = uint16(len(outbuf))
|
||||
message.buf = uintptr(unsafe.Pointer(&hdrp.Data))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&message))
|
||||
packets.nmsg = 1
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteByteToReg(addr, reg, value byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
outbuf := [...]byte{
|
||||
reg,
|
||||
value,
|
||||
}
|
||||
|
||||
var message i2c_msg
|
||||
message.addr = uint16(addr)
|
||||
message.flags = 0
|
||||
message.len = uint16(len(outbuf))
|
||||
message.buf = uintptr(unsafe.Pointer(&outbuf))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&message))
|
||||
packets.nmsg = 1
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteWordToReg(addr, reg byte, value uint16) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
outbuf := [...]byte{
|
||||
reg,
|
||||
byte(value >> 8),
|
||||
byte(value),
|
||||
}
|
||||
|
||||
var messages i2c_msg
|
||||
messages.addr = uint16(addr)
|
||||
messages.flags = 0
|
||||
messages.len = uint16(len(outbuf))
|
||||
messages.buf = uintptr(unsafe.Pointer(&outbuf))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&messages))
|
||||
packets.nmsg = 1
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
43
host/generic/linux/i2c/i2c.go
Normal file
43
host/generic/linux/i2c/i2c.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Package i2c enables gophers i2c speaking ability.
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/kidoman/embd/i2c"
|
||||
)
|
||||
|
||||
type I2C struct {
|
||||
busMap map[byte]*bus
|
||||
busMapLock sync.Mutex
|
||||
}
|
||||
|
||||
func New() *I2C {
|
||||
return &I2C{
|
||||
busMap: make(map[byte]*bus),
|
||||
}
|
||||
}
|
||||
|
||||
func (i *I2C) Bus(l byte) i2c.Bus {
|
||||
i.busMapLock.Lock()
|
||||
defer i.busMapLock.Unlock()
|
||||
|
||||
var b *bus
|
||||
|
||||
if b = i.busMap[l]; b == nil {
|
||||
b = &bus{l: l}
|
||||
i.busMap[l] = b
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (i *I2C) Close() error {
|
||||
for _, b := range i.busMap {
|
||||
b.Close()
|
||||
|
||||
delete(i.busMap, b.l)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
45
host/rpi/data.go
Normal file
45
host/rpi/data.go
Normal file
@ -0,0 +1,45 @@
|
||||
package rpi
|
||||
|
||||
import (
|
||||
"github.com/kidoman/embd/host/generic/linux/gpio"
|
||||
)
|
||||
|
||||
var rev1Pins = gpio.PinMap{
|
||||
&gpio.PinDesc{0, []string{"P1_3", "GPIO_0", "SDA", "I2C0_SDA"}, gpio.Normal | gpio.I2C},
|
||||
&gpio.PinDesc{1, []string{"P1_5", "GPIO_1", "SCL", "I2C0_SCL"}, gpio.Normal | gpio.I2C},
|
||||
&gpio.PinDesc{4, []string{"P1_7", "GPIO_4", "GPCLK0"}, gpio.Normal},
|
||||
&gpio.PinDesc{14, []string{"P1_8", "GPIO_14", "TXD", "UART0_TXD"}, gpio.Normal | gpio.UART},
|
||||
&gpio.PinDesc{15, []string{"P1_10", "GPIO_15", "RXD", "UART0_RXD"}, gpio.Normal | gpio.UART},
|
||||
&gpio.PinDesc{17, []string{"P1_11", "GPIO_17"}, gpio.Normal},
|
||||
&gpio.PinDesc{18, []string{"P1_12", "GPIO_18", "PCM_CLK"}, gpio.Normal},
|
||||
&gpio.PinDesc{21, []string{"P1_13", "GPIO_21"}, gpio.Normal},
|
||||
&gpio.PinDesc{22, []string{"P1_15", "GPIO_22"}, gpio.Normal},
|
||||
&gpio.PinDesc{23, []string{"P1_16", "GPIO_23"}, gpio.Normal},
|
||||
&gpio.PinDesc{24, []string{"P1_18", "GPIO_24"}, gpio.Normal},
|
||||
&gpio.PinDesc{10, []string{"P1_19", "GPIO_10", "MOSI", "SPI0_MOSI"}, gpio.Normal | gpio.SPI},
|
||||
&gpio.PinDesc{9, []string{"P1_21", "GPIO_9", "MISO", "SPI0_MISO"}, gpio.Normal | gpio.SPI},
|
||||
&gpio.PinDesc{25, []string{"P1_22", "GPIO_25"}, gpio.Normal},
|
||||
&gpio.PinDesc{11, []string{"P1_23", "GPIO_11", "SCLK", "SPI0_SCLK"}, gpio.Normal | gpio.SPI},
|
||||
&gpio.PinDesc{8, []string{"P1_24", "GPIO_8", "CE0", "SPI0_CE0_N"}, gpio.Normal | gpio.SPI},
|
||||
&gpio.PinDesc{7, []string{"P1_26", "GPIO_7", "CE1", "SPI0_CE1_N"}, gpio.Normal | gpio.SPI},
|
||||
}
|
||||
|
||||
var rev2Pins = gpio.PinMap{
|
||||
&gpio.PinDesc{2, []string{"P1_3", "GPIO_2", "SDA", "I2C1_SDA"}, gpio.Normal | gpio.I2C},
|
||||
&gpio.PinDesc{3, []string{"P1_5", "GPIO_3", "SCL", "I2C1_SCL"}, gpio.Normal | gpio.I2C},
|
||||
&gpio.PinDesc{4, []string{"P1_7", "GPIO_4", "GPCLK0"}, gpio.Normal},
|
||||
&gpio.PinDesc{14, []string{"P1_8", "GPIO_14", "TXD", "UART0_TXD"}, gpio.Normal | gpio.UART},
|
||||
&gpio.PinDesc{15, []string{"P1_10", "GPIO_15", "RXD", "UART0_RXD"}, gpio.Normal | gpio.UART},
|
||||
&gpio.PinDesc{17, []string{"P1_11", "GPIO_17"}, gpio.Normal},
|
||||
&gpio.PinDesc{18, []string{"P1_12", "GPIO_18", "PCM_CLK"}, gpio.Normal},
|
||||
&gpio.PinDesc{27, []string{"P1_13", "GPIO_27"}, gpio.Normal},
|
||||
&gpio.PinDesc{22, []string{"P1_15", "GPIO_22"}, gpio.Normal},
|
||||
&gpio.PinDesc{23, []string{"P1_16", "GPIO_23"}, gpio.Normal},
|
||||
&gpio.PinDesc{24, []string{"P1_18", "GPIO_24"}, gpio.Normal},
|
||||
&gpio.PinDesc{10, []string{"P1_19", "GPIO_10", "MOSI", "SPI0_MOSI"}, gpio.Normal | gpio.SPI},
|
||||
&gpio.PinDesc{9, []string{"P1_21", "GPIO_9", "MISO", "SPI0_MISO"}, gpio.Normal | gpio.SPI},
|
||||
&gpio.PinDesc{25, []string{"P1_22", "GPIO_25"}, gpio.Normal},
|
||||
&gpio.PinDesc{11, []string{"P1_23", "GPIO_11", "SCLK", "SPI0_SCLK"}, gpio.Normal | gpio.SPI},
|
||||
&gpio.PinDesc{8, []string{"P1_24", "GPIO_8", "CE0", "SPI0_CE0_N"}, gpio.Normal | gpio.SPI},
|
||||
&gpio.PinDesc{7, []string{"P1_26", "GPIO_7", "CE1", "SPI0_CE1_N"}, gpio.Normal | gpio.SPI},
|
||||
}
|
29
host/rpi/descriptor.go
Normal file
29
host/rpi/descriptor.go
Normal file
@ -0,0 +1,29 @@
|
||||
package rpi
|
||||
|
||||
import (
|
||||
"github.com/kidoman/embd/gpio"
|
||||
lgpio "github.com/kidoman/embd/host/generic/linux/gpio"
|
||||
li2c "github.com/kidoman/embd/host/generic/linux/i2c"
|
||||
"github.com/kidoman/embd/i2c"
|
||||
)
|
||||
|
||||
type descriptor struct {
|
||||
rev int
|
||||
}
|
||||
|
||||
func (d *descriptor) GPIO() gpio.GPIO {
|
||||
var pins = rev1Pins
|
||||
if d.rev > 1 {
|
||||
pins = rev2Pins
|
||||
}
|
||||
|
||||
return lgpio.New(pins)
|
||||
}
|
||||
|
||||
func (d *descriptor) I2C() i2c.I2C {
|
||||
return li2c.New()
|
||||
}
|
||||
|
||||
func Descriptor(rev int) *descriptor {
|
||||
return &descriptor{rev}
|
||||
}
|
376
i2c/i2c.go
376
i2c/i2c.go
@ -1,26 +1,6 @@
|
||||
// Package i2c enables gophers i2c speaking ability.
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
delay = 20
|
||||
|
||||
slaveCmd = 0x0703 // Cmd to set slave address
|
||||
rdrwCmd = 0x0707 // Cmd to read/write data together
|
||||
|
||||
rd = 0x0001
|
||||
)
|
||||
|
||||
// A Bus implements access to the I2C two wire bus.
|
||||
type Bus interface {
|
||||
// ReadByte reads a byte from the given address.
|
||||
ReadByte(addr byte) (value byte, err error)
|
||||
@ -44,356 +24,8 @@ type Bus interface {
|
||||
WriteWordToReg(addr, reg byte, value uint16) error
|
||||
}
|
||||
|
||||
type i2c_msg struct {
|
||||
addr uint16
|
||||
flags uint16
|
||||
len uint16
|
||||
buf uintptr
|
||||
}
|
||||
|
||||
type i2c_rdwr_ioctl_data struct {
|
||||
msgs uintptr
|
||||
nmsg uint32
|
||||
}
|
||||
|
||||
var busMap map[byte]*bus
|
||||
var busMapLock sync.Mutex
|
||||
|
||||
// Default instance of the i2c bus
|
||||
var Default Bus
|
||||
|
||||
type bus struct {
|
||||
l byte
|
||||
file *os.File
|
||||
addr byte
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func init() {
|
||||
busMap = make(map[byte]*bus)
|
||||
Default = NewBus(1)
|
||||
}
|
||||
|
||||
// NewBus creates a new I2C bus interface. The l variable
|
||||
// controls which bus we connect to.
|
||||
//
|
||||
// For the newer RaspberryPi, the number is 1 (earlier model uses 0.)
|
||||
func NewBus(l byte) Bus {
|
||||
busMapLock.Lock()
|
||||
defer busMapLock.Unlock()
|
||||
|
||||
var b *bus
|
||||
|
||||
if b = busMap[l]; b == nil {
|
||||
b = &bus{l: l}
|
||||
busMap[l] = b
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *bus) init() (err error) {
|
||||
if b.file != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if b.file, err = os.OpenFile(fmt.Sprintf("/dev/i2c-%v", b.l), os.O_RDWR, os.ModeExclusive); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) setAddress(addr byte) (err error) {
|
||||
if addr != b.addr {
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), slaveCmd, uintptr(addr)); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
b.addr = addr
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) ReadByte(addr byte) (value byte, err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.init(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bytes := make([]byte, 1)
|
||||
n, err := b.file.Read(bytes)
|
||||
|
||||
if n != 1 {
|
||||
err = fmt.Errorf("i2c: Unexpected number (%v) of bytes read", n)
|
||||
}
|
||||
|
||||
value = bytes[0]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteByte(addr, value byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.init(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
n, err := b.file.Write([]byte{value})
|
||||
|
||||
if n != 1 {
|
||||
err = fmt.Errorf("i2c: Unexpected number (%v) of bytes written in WriteByte", n)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteBytes(addr byte, value []byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.init(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range value {
|
||||
n, err := b.file.Write([]byte{value[i]})
|
||||
|
||||
if n != 1 {
|
||||
return fmt.Errorf("i2c: Unexpected number (%v) of bytes written in WriteBytes", n)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time.Sleep(delay * time.Millisecond)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *bus) ReadFromReg(addr, reg byte, value []byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.init(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&value))
|
||||
|
||||
var messages [2]i2c_msg
|
||||
messages[0].addr = uint16(addr)
|
||||
messages[0].flags = 0
|
||||
messages[0].len = 1
|
||||
messages[0].buf = uintptr(unsafe.Pointer(®))
|
||||
|
||||
messages[1].addr = uint16(addr)
|
||||
messages[1].flags = rd
|
||||
messages[1].len = uint16(len(value))
|
||||
messages[1].buf = uintptr(unsafe.Pointer(hdrp.Data))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&messages))
|
||||
packets.nmsg = 2
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
return syscall.Errno(errno)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *bus) ReadByteFromReg(addr, reg byte) (value byte, err error) {
|
||||
buf := make([]byte, 1)
|
||||
if err = b.ReadFromReg(addr, reg, buf); err != nil {
|
||||
return
|
||||
}
|
||||
value = buf[0]
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) ReadWordFromReg(addr, reg byte) (value uint16, err error) {
|
||||
buf := make([]byte, 2)
|
||||
if err = b.ReadFromReg(addr, reg, buf); err != nil {
|
||||
return
|
||||
}
|
||||
value = uint16((uint16(buf[0]) << 8) | uint16(buf[1]))
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteToReg(addr, reg byte, value []byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.init(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
outbuf := append([]byte{reg}, value...)
|
||||
|
||||
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&outbuf))
|
||||
|
||||
var message i2c_msg
|
||||
message.addr = uint16(addr)
|
||||
message.flags = 0
|
||||
message.len = uint16(len(outbuf))
|
||||
message.buf = uintptr(unsafe.Pointer(&hdrp.Data))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&message))
|
||||
packets.nmsg = 1
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteByteToReg(addr, reg, value byte) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.init(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
outbuf := [...]byte{
|
||||
reg,
|
||||
value,
|
||||
}
|
||||
|
||||
var message i2c_msg
|
||||
message.addr = uint16(addr)
|
||||
message.flags = 0
|
||||
message.len = uint16(len(outbuf))
|
||||
message.buf = uintptr(unsafe.Pointer(&outbuf))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&message))
|
||||
packets.nmsg = 1
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *bus) WriteWordToReg(addr, reg byte, value uint16) (err error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if err = b.init(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = b.setAddress(addr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
outbuf := [...]byte{
|
||||
reg,
|
||||
byte(value >> 8),
|
||||
byte(value),
|
||||
}
|
||||
|
||||
var messages i2c_msg
|
||||
messages.addr = uint16(addr)
|
||||
messages.flags = 0
|
||||
messages.len = uint16(len(outbuf))
|
||||
messages.buf = uintptr(unsafe.Pointer(&outbuf))
|
||||
|
||||
var packets i2c_rdwr_ioctl_data
|
||||
|
||||
packets.msgs = uintptr(unsafe.Pointer(&messages))
|
||||
packets.nmsg = 1
|
||||
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, b.file.Fd(), rdrwCmd, uintptr(unsafe.Pointer(&packets))); errno != 0 {
|
||||
err = syscall.Errno(errno)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReadByte reads a byte from the given address.
|
||||
func ReadByte(addr byte) (value byte, err error) {
|
||||
return Default.ReadByte(addr)
|
||||
}
|
||||
|
||||
// WriteByte writes a byte to the given address.
|
||||
func WriteByte(addr, value byte) error {
|
||||
return Default.WriteByte(addr, value)
|
||||
}
|
||||
|
||||
// WriteBytes writes a slice bytes to the given address.
|
||||
func WriteBytes(addr byte, value []byte) error {
|
||||
return Default.WriteBytes(addr, value)
|
||||
}
|
||||
|
||||
// ReadFromReg reads n (len(value)) bytes from the given address and register.
|
||||
func ReadFromReg(addr, reg byte, value []byte) error {
|
||||
return Default.ReadFromReg(addr, reg, value)
|
||||
}
|
||||
|
||||
// ReadByteFromReg reads a byte from the given address and register.
|
||||
func ReadByteFromReg(addr, reg byte) (value byte, err error) {
|
||||
return Default.ReadByteFromReg(addr, reg)
|
||||
}
|
||||
|
||||
// ReadU16FromReg reads a unsigned 16 bit integer from the given address and register.
|
||||
func ReadWordFromReg(addr, reg byte) (value uint16, err error) {
|
||||
return Default.ReadWordFromReg(addr, reg)
|
||||
}
|
||||
|
||||
// WriteToReg writes len(value) bytes to the given address and register.
|
||||
func WriteToReg(addr, reg byte, value []byte) error {
|
||||
return Default.WriteToReg(addr, reg, value)
|
||||
}
|
||||
|
||||
// WriteByteToReg writes a byte to the given address and register.
|
||||
func WriteByteToReg(addr, reg, value byte) error {
|
||||
return Default.WriteByteToReg(addr, reg, value)
|
||||
}
|
||||
|
||||
// WriteU16ToReg
|
||||
func WriteWordToReg(addr, reg byte, value uint16) error {
|
||||
return Default.WriteWordToReg(addr, reg, value)
|
||||
type I2C interface {
|
||||
Bus(l byte) Bus
|
||||
|
||||
Close() error
|
||||
}
|
||||
|
2
samples/.gitignore
vendored
Normal file
2
samples/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
gpio
|
||||
gpiodetect
|
@ -3,13 +3,17 @@ package main
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd/i2c"
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/sensor/bh1750fvi"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
sensor := bh1750fvi.New(bh1750fvi.High, bus)
|
||||
defer sensor.Close()
|
||||
|
@ -3,13 +3,17 @@ package main
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd/i2c"
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/sensor/bmp085"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
baro := bmp085.New(bus)
|
||||
defer baro.Close()
|
||||
|
@ -3,13 +3,17 @@ package main
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd/i2c"
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/sensor/bmp180"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
baro := bmp180.New(bus)
|
||||
defer baro.Close()
|
||||
|
@ -3,31 +3,31 @@ package main
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd/gpio"
|
||||
"github.com/kidoman/embd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
io := gpio.New()
|
||||
defer io.Close()
|
||||
gpio, err := embd.NewGPIO()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer gpio.Close()
|
||||
|
||||
pin, err := io.Pin("MOSI")
|
||||
led, err := gpio.DigitalPin(10)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := pin.Output(); err != nil {
|
||||
if err := led.SetDir(embd.Out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := pin.ActiveLow(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := pin.Low(); err != nil {
|
||||
if err := led.Write(embd.High); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
if err := pin.Input(); err != nil {
|
||||
if err := led.SetDir(embd.In); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
51
samples/gpiodetect.go
Normal file
51
samples/gpiodetect.go
Normal file
@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/host"
|
||||
)
|
||||
|
||||
func main() {
|
||||
h, _, err := host.Detect()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var pinNo interface{}
|
||||
|
||||
switch h {
|
||||
case host.BBB:
|
||||
pinNo = "P9_31"
|
||||
case host.RPi:
|
||||
pinNo = 10
|
||||
default:
|
||||
panic("host not supported (yet :P)")
|
||||
}
|
||||
|
||||
gpio, err := embd.NewGPIO()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer gpio.Close()
|
||||
|
||||
led, err := gpio.DigitalPin(pinNo)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer led.Close()
|
||||
|
||||
if err := led.SetDir(embd.Out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := led.Write(embd.High); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
if err := led.SetDir(embd.In); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
@ -5,13 +5,17 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd/i2c"
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/sensor/l3gd20"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
gyro := l3gd20.New(bus, l3gd20.R250DPS)
|
||||
gyro.Debug = true
|
||||
|
@ -4,12 +4,18 @@ import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd/i2c"
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/sensor/lsm303"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer i2c.Close()
|
||||
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
mems := lsm303.New(bus)
|
||||
defer mems.Close()
|
||||
|
@ -6,12 +6,17 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/controller/mcp4725"
|
||||
"github.com/kidoman/embd/i2c"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
dac := mcp4725.New(bus, 0x62)
|
||||
defer dac.Close()
|
||||
|
@ -6,14 +6,20 @@ import (
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/controller/pca9685"
|
||||
"github.com/kidoman/embd/i2c"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pca9685 := pca9685.New(bus, 0x41, 1000)
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
pca9685 := pca9685.New(bus, 0x41)
|
||||
pca9685.Freq = 1000
|
||||
pca9685.Debug = true
|
||||
defer pca9685.Close()
|
||||
|
||||
|
@ -1,20 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/controller/pca9685"
|
||||
"github.com/kidoman/embd/i2c"
|
||||
"github.com/kidoman/embd/motion/servo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pwm := pca9685.New(bus, 0x41, 50)
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
pwm := pca9685.New(bus, 0x41)
|
||||
pwm.Freq = 50
|
||||
pwm.Debug = true
|
||||
defer pwm.Close()
|
||||
|
||||
|
@ -5,12 +5,17 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/kidoman/embd/i2c"
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/sensor/tmp006"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bus := i2c.NewBus(1)
|
||||
i2c, err := embd.NewI2C()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bus := i2c.Bus(1)
|
||||
|
||||
sensor := tmp006.New(bus, 0x40)
|
||||
if status, err := sensor.Present(); err != nil || !status {
|
||||
|
@ -4,15 +4,27 @@ import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/sensor/us020"
|
||||
"github.com/stianeikeland/go-rpio"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rpio.Open()
|
||||
defer rpio.Close()
|
||||
gpio, err := embd.NewGPIO()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer gpio.Close()
|
||||
|
||||
rf := us020.New(10, 9, nil)
|
||||
echoPin, err := gpio.DigitalPin(10)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
triggerPin, err := gpio.DigitalPin(9)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rf := us020.New(echoPin, triggerPin, nil)
|
||||
defer rf.Close()
|
||||
|
||||
for {
|
||||
|
@ -53,9 +53,6 @@ type bh1750fvi struct {
|
||||
poll int
|
||||
}
|
||||
|
||||
// Default instance for BH1750FVI sensor
|
||||
var Default = New(High, i2c.Default)
|
||||
|
||||
// Supports three modes:
|
||||
// "H" -> High resolution mode (1lx), takes 120ms (recommended).
|
||||
// "H2" -> High resolution mode 2 (0.5lx), takes 120ms (only use for low light).
|
||||
@ -149,23 +146,3 @@ func (d *bh1750fvi) Close() {
|
||||
func (d *bh1750fvi) SetPollDelay(delay int) {
|
||||
d.poll = delay
|
||||
}
|
||||
|
||||
// SetPollDelay sets the delay between run of data acquisition loop.
|
||||
func SetPollDelay(delay int) {
|
||||
Default.SetPollDelay(delay)
|
||||
}
|
||||
|
||||
// Lighting returns the ambient lighting in lx.
|
||||
func Lighting() (lighting float64, err error) {
|
||||
return Default.Lighting()
|
||||
}
|
||||
|
||||
// Run starts continuous sensor data acquisition loop.
|
||||
func Run() (err error) {
|
||||
return Default.Run()
|
||||
}
|
||||
|
||||
// Close.
|
||||
func Close() {
|
||||
Default.Close()
|
||||
}
|
||||
|
@ -76,9 +76,6 @@ type bmp085 struct {
|
||||
debug bool
|
||||
}
|
||||
|
||||
// Default instance of the BMP085 sensor.
|
||||
var Default = New(i2c.Default)
|
||||
|
||||
// New creates a new BMP085 interface. The bus variable controls
|
||||
// the I2C bus used to communicate with the device.
|
||||
func New(bus i2c.Bus) BMP085 {
|
||||
@ -440,33 +437,3 @@ func (d *bmp085) Close() {
|
||||
d.quit <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// SetPollDelay sets the delay between runs of the data acquisition loop.
|
||||
func SetPollDelay(delay int) {
|
||||
Default.SetPollDelay(delay)
|
||||
}
|
||||
|
||||
// Temperature returns the current temperature reading.
|
||||
func Temperature() (temp float64, err error) {
|
||||
return Default.Temperature()
|
||||
}
|
||||
|
||||
// Pressure returns the current pressure reading.
|
||||
func Pressure() (pressure int, err error) {
|
||||
return Default.Pressure()
|
||||
}
|
||||
|
||||
// Altitude returns the current altitude reading.
|
||||
func Altitude() (altitude float64, err error) {
|
||||
return Default.Altitude()
|
||||
}
|
||||
|
||||
// Run starts the sensor data acquisition loop.
|
||||
func Run() (err error) {
|
||||
return Default.Run()
|
||||
}
|
||||
|
||||
// Close.
|
||||
func Close() {
|
||||
Default.Close()
|
||||
}
|
||||
|
@ -76,9 +76,6 @@ type bmp180 struct {
|
||||
debug bool
|
||||
}
|
||||
|
||||
// Default instance of the BMP180 sensor.
|
||||
var Default = New(i2c.Default)
|
||||
|
||||
// New creates a new BMP180 interface. The bus variable controls
|
||||
// the I2C bus used to communicate with the device.
|
||||
func New(bus i2c.Bus) BMP180 {
|
||||
@ -440,33 +437,3 @@ func (d *bmp180) Close() {
|
||||
d.quit <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// SetPollDelay sets the delay between runs of the data acquisition loop.
|
||||
func SetPollDelay(delay int) {
|
||||
Default.SetPollDelay(delay)
|
||||
}
|
||||
|
||||
// Temperature returns the current temperature reading.
|
||||
func Temperature() (temp float64, err error) {
|
||||
return Default.Temperature()
|
||||
}
|
||||
|
||||
// Pressure returns the current pressure reading.
|
||||
func Pressure() (pressure int, err error) {
|
||||
return Default.Pressure()
|
||||
}
|
||||
|
||||
// Altitude returns the current altitude reading.
|
||||
func Altitude() (altitude float64, err error) {
|
||||
return Default.Altitude()
|
||||
}
|
||||
|
||||
// Run starts the sensor data acquisition loop.
|
||||
func Run() (err error) {
|
||||
return Default.Run()
|
||||
}
|
||||
|
||||
// Close.
|
||||
func Close() {
|
||||
Default.Close()
|
||||
}
|
||||
|
@ -70,9 +70,6 @@ type lsm303 struct {
|
||||
debug bool
|
||||
}
|
||||
|
||||
// Default instance of the LSM303 sensor.
|
||||
var Default = New(i2c.Default)
|
||||
|
||||
// New creates a new LSM303 interface. The bus variable controls
|
||||
// the I2C bus used to communicate with the device.
|
||||
func New(bus i2c.Bus) LSM303 {
|
||||
@ -185,23 +182,3 @@ func (d *lsm303) Close() (err error) {
|
||||
err = d.bus.WriteByteToReg(magAddress, magModeReg, MagSleep)
|
||||
return
|
||||
}
|
||||
|
||||
// SetPollDelay sets the delay between runs of the data acquisition loop.
|
||||
func SetPollDelay(delay int) {
|
||||
Default.SetPollDelay(delay)
|
||||
}
|
||||
|
||||
// Heading returns the current heading [0, 360).
|
||||
func Heading() (heading float64, err error) {
|
||||
return Default.Heading()
|
||||
}
|
||||
|
||||
// Run starts the sensor data acquisition loop.
|
||||
func Run() (err error) {
|
||||
return Default.Run()
|
||||
}
|
||||
|
||||
// Close closes the sensor data acquisition loop and put the LSM303 into sleep mode.
|
||||
func Close() (err error) {
|
||||
return Default.Close()
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/stianeikeland/go-rpio"
|
||||
"github.com/kidoman/embd"
|
||||
"github.com/kidoman/embd/gpio"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -29,13 +30,10 @@ var NullThermometer = &nullThermometer{}
|
||||
|
||||
// US020 represents a US020 ultrasonic range finder.
|
||||
type US020 struct {
|
||||
EchoPinNumber, TriggerPinNumber int
|
||||
EchoPin, TriggerPin gpio.DigitalPin
|
||||
|
||||
Thermometer Thermometer
|
||||
|
||||
echoPin rpio.Pin
|
||||
triggerPin rpio.Pin
|
||||
|
||||
speedSound float64
|
||||
|
||||
initialized bool
|
||||
@ -46,8 +44,8 @@ type US020 struct {
|
||||
|
||||
// New creates a new US020 interface. The bus variable controls
|
||||
// the I2C bus used to communicate with the device.
|
||||
func New(e, t int, thermometer Thermometer) *US020 {
|
||||
return &US020{EchoPinNumber: e, TriggerPinNumber: t, Thermometer: thermometer}
|
||||
func New(echoPin, triggerPin gpio.DigitalPin, thermometer Thermometer) *US020 {
|
||||
return &US020{EchoPin: echoPin, TriggerPin: triggerPin, Thermometer: thermometer}
|
||||
}
|
||||
|
||||
func (d *US020) setup() (err error) {
|
||||
@ -61,11 +59,8 @@ func (d *US020) setup() (err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
d.echoPin = rpio.Pin(d.EchoPinNumber) // ECHO port on the US020
|
||||
d.triggerPin = rpio.Pin(d.TriggerPinNumber) // TRIGGER port on the US020
|
||||
|
||||
d.echoPin.Input()
|
||||
d.triggerPin.Output()
|
||||
d.TriggerPin.SetDir(embd.Out)
|
||||
d.EchoPin.SetDir(embd.In)
|
||||
|
||||
if d.Thermometer == nil {
|
||||
d.Thermometer = NullThermometer
|
||||
@ -97,16 +92,24 @@ func (d *US020) Distance() (distance float64, err error) {
|
||||
}
|
||||
|
||||
// Generate a TRIGGER pulse
|
||||
d.triggerPin.High()
|
||||
d.TriggerPin.Write(gpio.High)
|
||||
time.Sleep(pulseDelay)
|
||||
d.triggerPin.Low()
|
||||
d.TriggerPin.Write(gpio.Low)
|
||||
|
||||
if d.Debug {
|
||||
log.Print("us020: waiting for echo to go high")
|
||||
}
|
||||
|
||||
// Wait until ECHO goes high
|
||||
for d.echoPin.Read() == rpio.Low {
|
||||
for {
|
||||
v, err := d.EchoPin.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if v != embd.Low {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
startTime := time.Now() // Record time when ECHO goes high
|
||||
@ -116,7 +119,15 @@ func (d *US020) Distance() (distance float64, err error) {
|
||||
}
|
||||
|
||||
// Wait until ECHO goes low
|
||||
for d.echoPin.Read() == rpio.High {
|
||||
for {
|
||||
v, err := d.EchoPin.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if v != embd.High {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
duration := time.Since(startTime) // Calculate time lapsed for ECHO to transition from high to low
|
||||
@ -129,5 +140,5 @@ func (d *US020) Distance() (distance float64, err error) {
|
||||
|
||||
// Close.
|
||||
func (d *US020) Close() {
|
||||
d.echoPin.Output()
|
||||
d.EchoPin.SetDir(embd.Out)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user