mirror of
https://github.com/kidoman/embd
synced 2024-12-22 04:40:04 +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()
|
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
|
package gpio
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Direction int
|
type Direction int
|
||||||
type State int
|
|
||||||
type Pull int
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Input Direction = iota
|
In Direction = iota
|
||||||
Output
|
Out
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Low State = iota
|
Low int = iota
|
||||||
High
|
High
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type DigitalPin interface {
|
||||||
PullOff Pull = iota
|
Write(val int) error
|
||||||
PullDown
|
Read() (int, error)
|
||||||
PullUp
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
SetDir(dir Direction) error
|
||||||
normal = 1 << iota
|
ActiveLow(b bool) error
|
||||||
i2c
|
|
||||||
spi
|
|
||||||
uart
|
|
||||||
)
|
|
||||||
|
|
||||||
type gpio struct {
|
Close() error
|
||||||
exporter, unexporter *os.File
|
|
||||||
|
|
||||||
initialized bool
|
|
||||||
|
|
||||||
pinMap pinMap
|
|
||||||
initializedPins map[int]*pin
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance *gpio
|
type GPIO interface {
|
||||||
var instanceLock sync.Mutex
|
DigitalPin(key interface{}) (DigitalPin, error)
|
||||||
|
|
||||||
var Default *gpio
|
Close() error
|
||||||
|
|
||||||
func New() *gpio {
|
|
||||||
instanceLock.Lock()
|
|
||||||
defer instanceLock.Unlock()
|
|
||||||
|
|
||||||
if instance == nil {
|
|
||||||
instance = &gpio{
|
|
||||||
pinMap: rev2Pins,
|
|
||||||
initializedPins: map[int]*pin{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return instance
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) init() (err error) {
|
|
||||||
if io.initialized {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if io.exporter, err = os.OpenFile("/sys/class/gpio/export", os.O_WRONLY, os.ModeExclusive); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if io.unexporter, err = os.OpenFile("/sys/class/gpio/unexport", os.O_WRONLY, os.ModeExclusive); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
io.initialized = true
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) lookupKey(key interface{}) (*pinDesc, bool) {
|
|
||||||
return io.pinMap.lookup(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) export(n int) (err error) {
|
|
||||||
_, err = io.exporter.WriteString(strconv.Itoa(n))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) unexport(n int) (err error) {
|
|
||||||
_, err = io.unexporter.WriteString(strconv.Itoa(n))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) pin(key interface{}) (pin *pin, err error) {
|
|
||||||
pd, found := io.lookupKey(key)
|
|
||||||
if !found {
|
|
||||||
err = fmt.Errorf("gpio: could not find pin matching %q", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
n := pd.n
|
|
||||||
|
|
||||||
var ok bool
|
|
||||||
if pin, ok = io.initializedPins[n]; ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if pd.caps&normal == 0 {
|
|
||||||
err = fmt.Errorf("gpio: sorry, pin %q cannot be used for GPIO", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if pd.caps != normal {
|
|
||||||
glog.Infof("gpio: pin %q is not a dedicated GPIO pin. please refer to the system reference manual for more details", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = io.export(n); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if pin, err = NewPin(n); err != nil {
|
|
||||||
io.unexport(n)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
io.initializedPins[n] = pin
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) Pin(key interface{}) (pin *pin, err error) {
|
|
||||||
if err = io.init(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return io.pin(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) Mode(key interface{}, dir Direction) (err error) {
|
|
||||||
if err = io.init(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var pin *pin
|
|
||||||
if pin, err = io.pin(key); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return pin.Mode(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) Input(key interface{}) error {
|
|
||||||
return io.Mode(key, Input)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) Output(key interface{}) error {
|
|
||||||
return io.Mode(key, Output)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) Read(key interface{}) (state State, err error) {
|
|
||||||
if err = io.init(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var pin *pin
|
|
||||||
if pin, err = io.pin(key); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return pin.Read()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) Write(key interface{}, state State) (err error) {
|
|
||||||
if err = io.init(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var pin *pin
|
|
||||||
if pin, err = io.pin(key); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return pin.Write(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) Low(key interface{}) error {
|
|
||||||
return io.Write(key, Low)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) High(key interface{}) error {
|
|
||||||
return io.Write(key, High)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) SetActiveLow(key interface{}, b bool) (err error) {
|
|
||||||
if err = io.init(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var pin *pin
|
|
||||||
if pin, err = io.pin(key); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return pin.SetActiveLow(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) ActiveLow(key interface{}) error {
|
|
||||||
return io.SetActiveLow(key, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) ActiveHigh(key interface{}) error {
|
|
||||||
return io.SetActiveLow(key, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpio) Close() {
|
|
||||||
for n := range io.initializedPins {
|
|
||||||
io.unexport(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
io.exporter.Close()
|
|
||||||
io.unexporter.Close()
|
|
||||||
}
|
}
|
||||||
|
149
gpio/pin.go
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 enables gophers i2c speaking ability.
|
||||||
package i2c
|
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 {
|
type Bus interface {
|
||||||
// ReadByte reads a byte from the given address.
|
// ReadByte reads a byte from the given address.
|
||||||
ReadByte(addr byte) (value byte, err error)
|
ReadByte(addr byte) (value byte, err error)
|
||||||
@ -44,356 +24,8 @@ type Bus interface {
|
|||||||
WriteWordToReg(addr, reg byte, value uint16) error
|
WriteWordToReg(addr, reg byte, value uint16) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type i2c_msg struct {
|
type I2C interface {
|
||||||
addr uint16
|
Bus(l byte) Bus
|
||||||
flags uint16
|
|
||||||
len uint16
|
Close() error
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
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 (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/i2c"
|
|
||||||
"github.com/kidoman/embd/sensor/bh1750fvi"
|
"github.com/kidoman/embd/sensor/bh1750fvi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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)
|
sensor := bh1750fvi.New(bh1750fvi.High, bus)
|
||||||
defer sensor.Close()
|
defer sensor.Close()
|
||||||
|
@ -3,13 +3,17 @@ package main
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/i2c"
|
|
||||||
"github.com/kidoman/embd/sensor/bmp085"
|
"github.com/kidoman/embd/sensor/bmp085"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
bus := i2c.NewBus(1)
|
i2c, err := embd.NewI2C()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bus := i2c.Bus(1)
|
||||||
|
|
||||||
baro := bmp085.New(bus)
|
baro := bmp085.New(bus)
|
||||||
defer baro.Close()
|
defer baro.Close()
|
||||||
|
@ -3,13 +3,17 @@ package main
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/i2c"
|
|
||||||
"github.com/kidoman/embd/sensor/bmp180"
|
"github.com/kidoman/embd/sensor/bmp180"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
bus := i2c.NewBus(1)
|
i2c, err := embd.NewI2C()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bus := i2c.Bus(1)
|
||||||
|
|
||||||
baro := bmp180.New(bus)
|
baro := bmp180.New(bus)
|
||||||
defer baro.Close()
|
defer baro.Close()
|
||||||
|
@ -3,31 +3,31 @@ package main
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kidoman/embd/gpio"
|
"github.com/kidoman/embd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
io := gpio.New()
|
gpio, err := embd.NewGPIO()
|
||||||
defer io.Close()
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer gpio.Close()
|
||||||
|
|
||||||
pin, err := io.Pin("MOSI")
|
led, err := gpio.DigitalPin(10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pin.Output(); err != nil {
|
if err := led.SetDir(embd.Out); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := pin.ActiveLow(); err != nil {
|
if err := led.Write(embd.High); err != nil {
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err := pin.Low(); err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
if err := pin.Input(); err != nil {
|
if err := led.SetDir(embd.In); err != nil {
|
||||||
panic(err)
|
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"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"time"
|
"time"
|
||||||
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/i2c"
|
|
||||||
"github.com/kidoman/embd/sensor/l3gd20"
|
"github.com/kidoman/embd/sensor/l3gd20"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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 := l3gd20.New(bus, l3gd20.R250DPS)
|
||||||
gyro.Debug = true
|
gyro.Debug = true
|
||||||
|
@ -4,12 +4,18 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kidoman/embd/i2c"
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/sensor/lsm303"
|
"github.com/kidoman/embd/sensor/lsm303"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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)
|
mems := lsm303.New(bus)
|
||||||
defer mems.Close()
|
defer mems.Close()
|
||||||
|
@ -6,12 +6,17 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
||||||
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/controller/mcp4725"
|
"github.com/kidoman/embd/controller/mcp4725"
|
||||||
"github.com/kidoman/embd/i2c"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
bus := i2c.NewBus(1)
|
i2c, err := embd.NewI2C()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bus := i2c.Bus(1)
|
||||||
|
|
||||||
dac := mcp4725.New(bus, 0x62)
|
dac := mcp4725.New(bus, 0x62)
|
||||||
defer dac.Close()
|
defer dac.Close()
|
||||||
|
@ -6,14 +6,20 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/controller/pca9685"
|
"github.com/kidoman/embd/controller/pca9685"
|
||||||
"github.com/kidoman/embd/i2c"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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
|
pca9685.Debug = true
|
||||||
defer pca9685.Close()
|
defer pca9685.Close()
|
||||||
|
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/controller/pca9685"
|
"github.com/kidoman/embd/controller/pca9685"
|
||||||
"github.com/kidoman/embd/i2c"
|
|
||||||
"github.com/kidoman/embd/motion/servo"
|
"github.com/kidoman/embd/motion/servo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
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
|
pwm.Debug = true
|
||||||
defer pwm.Close()
|
defer pwm.Close()
|
||||||
|
|
||||||
|
@ -5,12 +5,17 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
||||||
"github.com/kidoman/embd/i2c"
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/sensor/tmp006"
|
"github.com/kidoman/embd/sensor/tmp006"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
bus := i2c.NewBus(1)
|
i2c, err := embd.NewI2C()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bus := i2c.Bus(1)
|
||||||
|
|
||||||
sensor := tmp006.New(bus, 0x40)
|
sensor := tmp006.New(bus, 0x40)
|
||||||
if status, err := sensor.Present(); err != nil || !status {
|
if status, err := sensor.Present(); err != nil || !status {
|
||||||
|
@ -4,15 +4,27 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kidoman/embd"
|
||||||
"github.com/kidoman/embd/sensor/us020"
|
"github.com/kidoman/embd/sensor/us020"
|
||||||
"github.com/stianeikeland/go-rpio"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
rpio.Open()
|
gpio, err := embd.NewGPIO()
|
||||||
defer rpio.Close()
|
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()
|
defer rf.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -53,9 +53,6 @@ type bh1750fvi struct {
|
|||||||
poll int
|
poll int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default instance for BH1750FVI sensor
|
|
||||||
var Default = New(High, i2c.Default)
|
|
||||||
|
|
||||||
// Supports three modes:
|
// Supports three modes:
|
||||||
// "H" -> High resolution mode (1lx), takes 120ms (recommended).
|
// "H" -> High resolution mode (1lx), takes 120ms (recommended).
|
||||||
// "H2" -> High resolution mode 2 (0.5lx), takes 120ms (only use for low light).
|
// "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) {
|
func (d *bh1750fvi) SetPollDelay(delay int) {
|
||||||
d.poll = delay
|
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
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default instance of the BMP085 sensor.
|
|
||||||
var Default = New(i2c.Default)
|
|
||||||
|
|
||||||
// New creates a new BMP085 interface. The bus variable controls
|
// New creates a new BMP085 interface. The bus variable controls
|
||||||
// the I2C bus used to communicate with the device.
|
// the I2C bus used to communicate with the device.
|
||||||
func New(bus i2c.Bus) BMP085 {
|
func New(bus i2c.Bus) BMP085 {
|
||||||
@ -440,33 +437,3 @@ func (d *bmp085) Close() {
|
|||||||
d.quit <- struct{}{}
|
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
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default instance of the BMP180 sensor.
|
|
||||||
var Default = New(i2c.Default)
|
|
||||||
|
|
||||||
// New creates a new BMP180 interface. The bus variable controls
|
// New creates a new BMP180 interface. The bus variable controls
|
||||||
// the I2C bus used to communicate with the device.
|
// the I2C bus used to communicate with the device.
|
||||||
func New(bus i2c.Bus) BMP180 {
|
func New(bus i2c.Bus) BMP180 {
|
||||||
@ -440,33 +437,3 @@ func (d *bmp180) Close() {
|
|||||||
d.quit <- struct{}{}
|
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
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default instance of the LSM303 sensor.
|
|
||||||
var Default = New(i2c.Default)
|
|
||||||
|
|
||||||
// New creates a new LSM303 interface. The bus variable controls
|
// New creates a new LSM303 interface. The bus variable controls
|
||||||
// the I2C bus used to communicate with the device.
|
// the I2C bus used to communicate with the device.
|
||||||
func New(bus i2c.Bus) LSM303 {
|
func New(bus i2c.Bus) LSM303 {
|
||||||
@ -185,23 +182,3 @@ func (d *lsm303) Close() (err error) {
|
|||||||
err = d.bus.WriteByteToReg(magAddress, magModeReg, MagSleep)
|
err = d.bus.WriteByteToReg(magAddress, magModeReg, MagSleep)
|
||||||
return
|
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"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stianeikeland/go-rpio"
|
"github.com/kidoman/embd"
|
||||||
|
"github.com/kidoman/embd/gpio"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -29,13 +30,10 @@ var NullThermometer = &nullThermometer{}
|
|||||||
|
|
||||||
// US020 represents a US020 ultrasonic range finder.
|
// US020 represents a US020 ultrasonic range finder.
|
||||||
type US020 struct {
|
type US020 struct {
|
||||||
EchoPinNumber, TriggerPinNumber int
|
EchoPin, TriggerPin gpio.DigitalPin
|
||||||
|
|
||||||
Thermometer Thermometer
|
Thermometer Thermometer
|
||||||
|
|
||||||
echoPin rpio.Pin
|
|
||||||
triggerPin rpio.Pin
|
|
||||||
|
|
||||||
speedSound float64
|
speedSound float64
|
||||||
|
|
||||||
initialized bool
|
initialized bool
|
||||||
@ -46,8 +44,8 @@ type US020 struct {
|
|||||||
|
|
||||||
// New creates a new US020 interface. The bus variable controls
|
// New creates a new US020 interface. The bus variable controls
|
||||||
// the I2C bus used to communicate with the device.
|
// the I2C bus used to communicate with the device.
|
||||||
func New(e, t int, thermometer Thermometer) *US020 {
|
func New(echoPin, triggerPin gpio.DigitalPin, thermometer Thermometer) *US020 {
|
||||||
return &US020{EchoPinNumber: e, TriggerPinNumber: t, Thermometer: thermometer}
|
return &US020{EchoPin: echoPin, TriggerPin: triggerPin, Thermometer: thermometer}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *US020) setup() (err error) {
|
func (d *US020) setup() (err error) {
|
||||||
@ -61,11 +59,8 @@ func (d *US020) setup() (err error) {
|
|||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
d.echoPin = rpio.Pin(d.EchoPinNumber) // ECHO port on the US020
|
d.TriggerPin.SetDir(embd.Out)
|
||||||
d.triggerPin = rpio.Pin(d.TriggerPinNumber) // TRIGGER port on the US020
|
d.EchoPin.SetDir(embd.In)
|
||||||
|
|
||||||
d.echoPin.Input()
|
|
||||||
d.triggerPin.Output()
|
|
||||||
|
|
||||||
if d.Thermometer == nil {
|
if d.Thermometer == nil {
|
||||||
d.Thermometer = NullThermometer
|
d.Thermometer = NullThermometer
|
||||||
@ -97,16 +92,24 @@ func (d *US020) Distance() (distance float64, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate a TRIGGER pulse
|
// Generate a TRIGGER pulse
|
||||||
d.triggerPin.High()
|
d.TriggerPin.Write(gpio.High)
|
||||||
time.Sleep(pulseDelay)
|
time.Sleep(pulseDelay)
|
||||||
d.triggerPin.Low()
|
d.TriggerPin.Write(gpio.Low)
|
||||||
|
|
||||||
if d.Debug {
|
if d.Debug {
|
||||||
log.Print("us020: waiting for echo to go high")
|
log.Print("us020: waiting for echo to go high")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until ECHO goes 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
|
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
|
// 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
|
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.
|
// Close.
|
||||||
func (d *US020) Close() {
|
func (d *US020) Close() {
|
||||||
d.echoPin.Output()
|
d.EchoPin.SetDir(embd.Out)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user