bring in the idea of a hardware abstraction layer

This commit is contained in:
Karan Misra 2014-02-27 04:24:53 +05:30
parent b4de382833
commit b5e2d0acc7
35 changed files with 994 additions and 971 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.floo*
.vagrant/
Vagrantfile

2
doc.go
View File

@ -26,4 +26,4 @@ Find out the heading from the LSM303 magnetometer:
...
heading, err := lsm303.Heading()
*/
package rpi
package embd

View File

@ -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},
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -1,7 +0,0 @@
package gpio
type pinDesc struct {
n int
ids []string
caps int
}

View File

@ -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
View 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
View 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
View 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
}

View 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
}

View 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
}

View 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(&reg))
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
}

View 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
View 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
View 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}
}

View File

@ -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(&reg))
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
View File

@ -0,0 +1,2 @@
gpio
gpiodetect

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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
View 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)
}
}

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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 {

View File

@ -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 {

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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)
}