whatcanGOwrong
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/exp/io/i2c/driver"
|
||||
)
|
||||
|
||||
// Devfs is an I2C driver that works against the devfs.
|
||||
// You need to load the "i2c-dev" kernel module to use this driver.
|
||||
type Devfs struct {
|
||||
// Dev is the I2C bus device, e.g. /dev/i2c-1. Required.
|
||||
Dev string
|
||||
}
|
||||
|
||||
const (
|
||||
i2c_SLAVE = 0x0703 // TODO(jbd): Allow users to use I2C_SLAVE_FORCE?
|
||||
i2c_TENBIT = 0x0704
|
||||
)
|
||||
|
||||
// TODO(jbd): Support I2C_RETRIES and I2C_TIMEOUT at the driver and implementation level.
|
||||
|
||||
func (d *Devfs) Open(addr int, tenbit bool) (driver.Conn, error) {
|
||||
f, err := os.OpenFile(d.Dev, os.O_RDWR, os.ModeDevice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn := &devfsConn{f: f}
|
||||
if tenbit {
|
||||
if err := conn.ioctl(i2c_TENBIT, uintptr(1)); err != nil {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("cannot enable the 10-bit address mode on bus %v: %v", d.Dev, err)
|
||||
}
|
||||
}
|
||||
if err := conn.ioctl(i2c_SLAVE, uintptr(addr)); err != nil {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("error opening the address (%v) on the bus (%v): %v", addr, d.Dev, err)
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
type devfsConn struct {
|
||||
f *os.File
|
||||
}
|
||||
|
||||
func (c *devfsConn) Tx(w, r []byte) error {
|
||||
if w != nil {
|
||||
if _, err := c.f.Write(w); err != nil {
|
||||
return err
|
||||
}
|
||||
c.f.Sync()
|
||||
}
|
||||
if r != nil {
|
||||
if _, err := io.ReadFull(c.f, r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *devfsConn) Close() error {
|
||||
return c.f.Close()
|
||||
}
|
||||
|
||||
func (c *devfsConn) ioctl(arg1, arg2 uintptr) error {
|
||||
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, c.f.Fd(), arg1, arg2); errno != 0 {
|
||||
return syscall.Errno(errno)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/exp/io/i2c/driver"
|
||||
)
|
||||
|
||||
// Devfs is no-implementation so developers using cross compilation
|
||||
// can rely on local tools even though the real implementation isn't
|
||||
// available on their platform.
|
||||
type Devfs struct {
|
||||
Dev string
|
||||
}
|
||||
|
||||
func (d *Devfs) Open(addr int, tenbit bool) (driver.Conn, error) {
|
||||
return nil, errors.New("not implemented on this platform")
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package driver contains interfaces to be implemented by various I2C implementations.
|
||||
package driver // import "golang.org/x/exp/io/i2c/driver"
|
||||
|
||||
// Opener opens a connection to an I2C device to communicate with
|
||||
// the I2C address given. If the address is an 10-bit I2C address,
|
||||
// tenbit is true.
|
||||
type Opener interface {
|
||||
Open(addr int, tenbit bool) (Conn, error)
|
||||
}
|
||||
|
||||
// Conn represents an active connection to an I2C device.
|
||||
type Conn interface {
|
||||
// Tx first writes w (if not nil), then reads len(r)
|
||||
// bytes from device into r (if not nil) in a single
|
||||
// I2C transaction.
|
||||
Tx(w, r []byte) error
|
||||
|
||||
// Close closes the connection.
|
||||
Close() error
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package main contains a program that displays the IPv4 address
|
||||
// of the machine on an a Grove-LCD RGB backlight.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"golang.org/x/exp/io/i2c"
|
||||
)
|
||||
|
||||
const (
|
||||
DISPLAY_RGB_ADDR = 0x62
|
||||
DISPLAY_TEXT_ADDR = 0x3e
|
||||
)
|
||||
|
||||
func main() {
|
||||
d, err := i2c.Open(&i2c.Devfs{Dev: "/dev/i2c-1"}, DISPLAY_RGB_ADDR)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
td, err := i2c.Open(&i2c.Devfs{Dev: "/dev/i2c-1"}, DISPLAY_TEXT_ADDR)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Set the backlight color to 100,100,100.
|
||||
write(d, []byte{0, 0})
|
||||
write(d, []byte{1, 0})
|
||||
write(d, []byte{0x08, 0xaa})
|
||||
write(d, []byte{4, 100}) // R value
|
||||
write(d, []byte{3, 100}) // G value
|
||||
write(d, []byte{2, 100}) // B value
|
||||
|
||||
ip, err := resolveIP()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("host machine IP is %v\n", ip)
|
||||
|
||||
write(td, []byte{0x80, 0x02}) // return home
|
||||
write(td, []byte{0x80, 0x01}) // clean the display
|
||||
write(td, []byte{0x80, 0x08 | 0x04}) // no cursor
|
||||
write(td, []byte{0x80, 0x28}) // two lines
|
||||
|
||||
for _, s := range ip {
|
||||
write(td, []byte{0x40, byte(s)})
|
||||
}
|
||||
}
|
||||
|
||||
func write(d *i2c.Device, buf []byte) {
|
||||
err := d.Write(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func resolveIP() (string, error) {
|
||||
var ip net.IP
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, i := range ifaces {
|
||||
addrs, err := i.Addrs()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
ip = ip.To4()
|
||||
if ip != nil && ip.String() != "127.0.0.1" {
|
||||
return ip.String(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("cannot resolve the IP")
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package i2c_test
|
||||
|
||||
import (
|
||||
"golang.org/x/exp/io/i2c"
|
||||
)
|
||||
|
||||
func ExampleOpen() {
|
||||
d, err := i2c.Open(&i2c.Devfs{Dev: "/dev/i2c-1"}, 0x39)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// opens a 10-bit address
|
||||
d, err = i2c.Open(&i2c.Devfs{Dev: "/dev/i2c-1"}, i2c.TenBit(0x78))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_ = d
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package i2c allows users to read from and write to a slave I2C device.
|
||||
//
|
||||
// # Deprecated
|
||||
//
|
||||
// This package is not maintained anymore. An actively supported cross-platform
|
||||
// alternative is https://periph.io/.
|
||||
package i2c // import "golang.org/x/exp/io/i2c"
|
||||
|
||||
import (
|
||||
"golang.org/x/exp/io/i2c/driver"
|
||||
)
|
||||
|
||||
const tenbitMask = 1 << 12
|
||||
|
||||
// Device represents an I2C device. Devices must be closed once
|
||||
// they are no longer in use.
|
||||
type Device struct {
|
||||
conn driver.Conn
|
||||
}
|
||||
|
||||
// TenBit marks an I2C address as a 10-bit address.
|
||||
func TenBit(addr int) int {
|
||||
return addr | tenbitMask
|
||||
}
|
||||
|
||||
// Read reads len(buf) bytes from the device.
|
||||
func (d *Device) Read(buf []byte) error {
|
||||
return d.conn.Tx(nil, buf)
|
||||
}
|
||||
|
||||
// ReadReg is similar to Read but it reads from a register.
|
||||
func (d *Device) ReadReg(reg byte, buf []byte) error {
|
||||
return d.conn.Tx([]byte{reg}, buf)
|
||||
}
|
||||
|
||||
// Write writes the buffer to the device. If it is required to write to a
|
||||
// specific register, the register should be passed as the first byte in the
|
||||
// given buffer.
|
||||
func (d *Device) Write(buf []byte) (err error) {
|
||||
return d.conn.Tx(buf, nil)
|
||||
}
|
||||
|
||||
// WriteReg is similar to Write but writes to a register.
|
||||
func (d *Device) WriteReg(reg byte, buf []byte) (err error) {
|
||||
// TODO(jbd): Do not allocate, not optimal.
|
||||
return d.conn.Tx(append([]byte{reg}, buf...), nil)
|
||||
}
|
||||
|
||||
// Close closes the device and releases the underlying sources.
|
||||
func (d *Device) Close() error {
|
||||
return d.conn.Close()
|
||||
}
|
||||
|
||||
// Open opens a connection to an I2C device.
|
||||
// All devices must be closed once they are no longer in use.
|
||||
// For devices that use 10-bit I2C addresses, addr can be marked
|
||||
// as a 10-bit address with TenBit.
|
||||
func Open(o driver.Opener, addr int) (*Device, error) {
|
||||
unmasked, tenbit := resolveAddr(addr)
|
||||
conn, err := o.Open(unmasked, tenbit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Device{conn: conn}, nil
|
||||
}
|
||||
|
||||
// resolveAddr returns whether the addr is 10-bit masked or not.
|
||||
// It also returns the unmasked address.
|
||||
func resolveAddr(addr int) (unmasked int, tenbit bool) {
|
||||
return addr & (tenbitMask - 1), addr&tenbitMask == tenbitMask
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTenBit(t *testing.T) {
|
||||
tc := []struct {
|
||||
masked int
|
||||
addrWant int
|
||||
tenbitWant bool
|
||||
}{
|
||||
{TenBit(0x5), 0x5, true},
|
||||
{0x5, 0x5, false},
|
||||
{TenBit(0x200), 0x200, true},
|
||||
}
|
||||
|
||||
for _, tt := range tc {
|
||||
unmasked, tenbit := resolveAddr(tt.masked)
|
||||
if want, got := tt.tenbitWant, tenbit; got != want {
|
||||
t.Errorf("want address %x as 10-bit; got non 10-bit", tt.masked)
|
||||
}
|
||||
if want, got := tt.addrWant, unmasked; got != want {
|
||||
t.Errorf("want address %v; got %v", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package spi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/exp/io/spi/driver"
|
||||
)
|
||||
|
||||
const (
|
||||
devfs_MAGIC = 107
|
||||
|
||||
devfs_NRBITS = 8
|
||||
devfs_TYPEBITS = 8
|
||||
devfs_SIZEBITS = 13
|
||||
devfs_DIRBITS = 3
|
||||
|
||||
devfs_NRSHIFT = 0
|
||||
devfs_TYPESHIFT = devfs_NRSHIFT + devfs_NRBITS
|
||||
devfs_SIZESHIFT = devfs_TYPESHIFT + devfs_TYPEBITS
|
||||
devfs_DIRSHIFT = devfs_SIZESHIFT + devfs_SIZEBITS
|
||||
|
||||
devfs_READ = 2
|
||||
devfs_WRITE = 4
|
||||
)
|
||||
|
||||
type payload struct {
|
||||
tx uint64
|
||||
rx uint64
|
||||
length uint32
|
||||
speed uint32
|
||||
delay uint16
|
||||
bits uint8
|
||||
csChange uint8
|
||||
txNBits uint8
|
||||
rxNBits uint8
|
||||
pad uint16
|
||||
}
|
||||
|
||||
// Devfs is an SPI driver that works against the devfs.
|
||||
// You need to have loaded the "spidev" Linux module to use this driver.
|
||||
type Devfs struct {
|
||||
// Dev is the device to be opened.
|
||||
// Device name is usually in the /dev/spidev<bus>.<chip> format.
|
||||
// Required.
|
||||
Dev string
|
||||
|
||||
// Mode is the SPI mode. SPI mode is a combination of polarity and phases.
|
||||
// CPOL is the high order bit, CPHA is the low order. Pre-computed mode
|
||||
// values are Mode0, Mode1, Mode2 and Mode3. The value of the mode argument
|
||||
// can be overridden by the device's driver.
|
||||
// Required.
|
||||
Mode Mode
|
||||
|
||||
// MaxSpeed is the max clock speed (Hz) and can be overridden by the device's driver.
|
||||
// Required.
|
||||
MaxSpeed int64
|
||||
}
|
||||
|
||||
// Open opens the provided device with the specified options
|
||||
// and returns a connection.
|
||||
func (d *Devfs) Open() (driver.Conn, error) {
|
||||
f, err := os.OpenFile(d.Dev, os.O_RDWR, os.ModeDevice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn := &devfsConn{f: f}
|
||||
if err := conn.Configure(driver.Mode, int(d.Mode)); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := conn.Configure(driver.MaxSpeed, int(d.MaxSpeed)); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
type devfsConn struct {
|
||||
f *os.File
|
||||
mode uint8
|
||||
speed uint32
|
||||
bits uint8
|
||||
delay uint16
|
||||
csChange uint8
|
||||
}
|
||||
|
||||
func (c *devfsConn) Configure(k, v int) error {
|
||||
switch k {
|
||||
case driver.Mode:
|
||||
m := uint8(v)
|
||||
if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 1, 1), uintptr(unsafe.Pointer(&m))); err != nil {
|
||||
return fmt.Errorf("error setting mode to %v: %v", m, err)
|
||||
}
|
||||
c.mode = m
|
||||
case driver.Bits:
|
||||
b := uint8(v)
|
||||
if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 3, 1), uintptr(unsafe.Pointer(&b))); err != nil {
|
||||
return fmt.Errorf("error setting bits per word to %v: %v", b, err)
|
||||
}
|
||||
c.bits = b
|
||||
case driver.MaxSpeed:
|
||||
s := uint32(v)
|
||||
if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 4, 4), uintptr(unsafe.Pointer(&s))); err != nil {
|
||||
return fmt.Errorf("error setting speed to %v: %v", s, err)
|
||||
}
|
||||
c.speed = s
|
||||
case driver.Order:
|
||||
o := uint8(v)
|
||||
if err := c.ioctl(requestCode(devfs_WRITE, devfs_MAGIC, 2, 1), uintptr(unsafe.Pointer(&o))); err != nil {
|
||||
return fmt.Errorf("error setting bit order to %v: %v", o, err)
|
||||
}
|
||||
case driver.Delay:
|
||||
c.delay = uint16(v)
|
||||
case driver.CSChange:
|
||||
c.csChange = uint8(v)
|
||||
default:
|
||||
return fmt.Errorf("unknown key: %v", k)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *devfsConn) Tx(w, r []byte) error {
|
||||
if r == nil {
|
||||
r = make([]byte, len(w))
|
||||
}
|
||||
// TODO(jbd): len(w) == len(r)?
|
||||
// TODO(jbd): Allow nil w.
|
||||
p := payload{
|
||||
tx: uint64(uintptr(unsafe.Pointer(&w[0]))),
|
||||
rx: uint64(uintptr(unsafe.Pointer(&r[0]))),
|
||||
length: uint32(len(w)),
|
||||
speed: c.speed,
|
||||
delay: c.delay,
|
||||
bits: c.bits,
|
||||
csChange: c.csChange,
|
||||
}
|
||||
// TODO(jbd): Read from the device and fill rx.
|
||||
return c.ioctl(msgRequestCode(1), uintptr(unsafe.Pointer(&p)))
|
||||
}
|
||||
|
||||
func (c *devfsConn) Close() error {
|
||||
return c.f.Close()
|
||||
}
|
||||
|
||||
// requestCode returns the device specific request code for the specified direction,
|
||||
// type, number and size to be used in the ioctl call.
|
||||
func requestCode(dir, typ, nr, size uintptr) uintptr {
|
||||
return (dir << devfs_DIRSHIFT) | (typ << devfs_TYPESHIFT) | (nr << devfs_NRSHIFT) | (size << devfs_SIZESHIFT)
|
||||
}
|
||||
|
||||
// msgRequestCode returns the device specific value for the SPI
|
||||
// message payload to be used in the ioctl call.
|
||||
// n represents the number of messages.
|
||||
func msgRequestCode(n uint32) uintptr {
|
||||
return uintptr(0x40006B00 + (n * 0x200000))
|
||||
}
|
||||
|
||||
// ioctl makes an IOCTL on the open device file descriptor.
|
||||
func (c *devfsConn) ioctl(a1, a2 uintptr) error {
|
||||
_, _, errno := syscall.Syscall(
|
||||
syscall.SYS_IOCTL, c.f.Fd(), a1, a2,
|
||||
)
|
||||
if errno != 0 {
|
||||
return syscall.Errno(errno)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package spi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/exp/io/spi/driver"
|
||||
)
|
||||
|
||||
// Devfs is a no-implementation of an SPI driver that works against the devfs.
|
||||
// You need to have loaded the Linux "spidev" module to use this driver.
|
||||
type Devfs struct {
|
||||
// Dev is the device to be opened.
|
||||
// Device name is usually in the /dev/spidev<bus>.<chip> format.
|
||||
// Required.
|
||||
Dev string
|
||||
|
||||
// Mode is the SPI mode. SPI mode is a combination of polarity and phases.
|
||||
// CPOL is the high order bit, CPHA is the low order. Pre-computed mode
|
||||
// values are Mode0, Mode1, Mode2 and Mode3. The value of the mode argument
|
||||
// can be overridden by the device's driver.
|
||||
// Required.
|
||||
Mode Mode
|
||||
|
||||
// MaxSpeed is the max clock speed (Hz) and can be overridden by the device's driver.
|
||||
// Required.
|
||||
MaxSpeed int64
|
||||
}
|
||||
|
||||
// Open opens the provided device with the speicifed options
|
||||
// and returns a connection.
|
||||
func (d *Devfs) Open() (driver.Conn, error) {
|
||||
return nil, errors.New("not implemented on this platform")
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package driver contains interfaces to be implemented by various SPI implementations.
|
||||
package driver // import "golang.org/x/exp/io/spi/driver"
|
||||
|
||||
const (
|
||||
Mode = iota
|
||||
Bits
|
||||
MaxSpeed
|
||||
Order
|
||||
Delay
|
||||
CSChange
|
||||
)
|
||||
|
||||
// Opener is an interface to be implemented by the SPI driver to open
|
||||
// a connection to an SPI device.
|
||||
type Opener interface {
|
||||
Open() (Conn, error)
|
||||
}
|
||||
|
||||
// Conn is a connection to an SPI device.
|
||||
// TODO(jbd): Extend the interface to query configuration values.
|
||||
type Conn interface {
|
||||
// Configure configures the SPI device.
|
||||
//
|
||||
// Available configuration keys are:
|
||||
// - Mode, the SPI mode (valid values are 0, 1, 2 and 3).
|
||||
// - Bits, bits per word (default is 8-bit per word).
|
||||
// - Speed, the max clock speed (in Hz).
|
||||
// - Order, bit order to be used in transfers. Zero value represents
|
||||
// the MSB-first, non-zero values represent LSB-first encoding.
|
||||
// - Delay, the pause time between frames (in usecs).
|
||||
// Some SPI devices require a minimum amount of wait time after
|
||||
// each frame write. If set, Delay amount of usecs are inserted after
|
||||
// each write.
|
||||
// - CSChange, whether to leave the device's chipselect active after a Tx.
|
||||
//
|
||||
// SPI devices can override these values.
|
||||
Configure(k, v int) error
|
||||
|
||||
// Tx performs a SPI transaction: w is written if not nil, the result is
|
||||
// put into r if not nil. len(w) must be equal to len(r), otherwise the
|
||||
// driver should return an error.
|
||||
Tx(w, r []byte) error
|
||||
|
||||
// Close frees the underlying resources and closes the connection.
|
||||
Close() error
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package spi_test
|
||||
|
||||
import "golang.org/x/exp/io/spi"
|
||||
|
||||
// Example illustrates a program that drives an APA-102 LED strip.
|
||||
func Example() {
|
||||
dev, err := spi.Open(&spi.Devfs{
|
||||
Dev: "/dev/spidev0.1",
|
||||
Mode: spi.Mode3,
|
||||
MaxSpeed: 500000,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer dev.Close()
|
||||
|
||||
if err := dev.Tx([]byte{
|
||||
0, 0, 0, 0,
|
||||
0xff, 200, 0, 200,
|
||||
0xff, 200, 0, 200,
|
||||
0xe0, 200, 0, 200,
|
||||
0xff, 200, 0, 200,
|
||||
0xff, 8, 50, 0,
|
||||
0xff, 200, 0, 0,
|
||||
0xff, 0, 0, 0,
|
||||
0xff, 200, 0, 200,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
}, nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package spi allows users to read from and write to an SPI device.
|
||||
//
|
||||
// # Deprecated
|
||||
//
|
||||
// This package is not maintained anymore. An actively supported cross-platform
|
||||
// alternative is https://periph.io/.
|
||||
package spi // import "golang.org/x/exp/io/spi"
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/io/spi/driver"
|
||||
)
|
||||
|
||||
// Mode represents the SPI mode number where clock parity (CPOL)
|
||||
// is the high order and clock edge (CPHA) is the low order bit.
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
Mode0 = Mode(0)
|
||||
Mode1 = Mode(1)
|
||||
Mode2 = Mode(2)
|
||||
Mode3 = Mode(3)
|
||||
)
|
||||
|
||||
// Order is the bit justification to be used while transferring
|
||||
// words to the SPI device. MSB-first encoding is more popular
|
||||
// than LSB-first.
|
||||
type Order int
|
||||
|
||||
const (
|
||||
MSBFirst = Order(0)
|
||||
LSBFirst = Order(1)
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
conn driver.Conn
|
||||
}
|
||||
|
||||
// SetMode sets the SPI mode. SPI mode is a combination of polarity and phases.
|
||||
// CPOL is the high order bit, CPHA is the low order. Pre-computed mode
|
||||
// values are Mode0, Mode1, Mode2 and Mode3.
|
||||
// The value can be changed by SPI device's driver.
|
||||
func (d *Device) SetMode(mode Mode) error {
|
||||
return d.conn.Configure(driver.Mode, int(mode))
|
||||
}
|
||||
|
||||
// SetMaxSpeed sets the maximum clock speed in Hz.
|
||||
// The value can be overridden by SPI device's driver.
|
||||
func (d *Device) SetMaxSpeed(speed int) error {
|
||||
return d.conn.Configure(driver.MaxSpeed, speed)
|
||||
}
|
||||
|
||||
// SetBitsPerWord sets how many bits it takes to represent a word, e.g. 8 represents 8-bit words.
|
||||
// The default is 8 bits per word.
|
||||
func (d *Device) SetBitsPerWord(bits int) error {
|
||||
return d.conn.Configure(driver.Bits, bits)
|
||||
}
|
||||
|
||||
// SetBitOrder sets the bit justification used to transfer SPI words.
|
||||
// Valid values are MSBFirst and LSBFirst.
|
||||
func (d *Device) SetBitOrder(o Order) error {
|
||||
return d.conn.Configure(driver.Order, int(o))
|
||||
}
|
||||
|
||||
// SetDelay sets the amount of pause will be added after each frame write.
|
||||
func (d *Device) SetDelay(t time.Duration) error {
|
||||
return d.conn.Configure(driver.Delay, int(t.Nanoseconds()/1000))
|
||||
}
|
||||
|
||||
// SetCSChange sets whether to leave the chipselect enabled after a Tx.
|
||||
func (d *Device) SetCSChange(leaveEnabled bool) error {
|
||||
v := 0
|
||||
if leaveEnabled {
|
||||
v = 1
|
||||
}
|
||||
return d.conn.Configure(driver.CSChange, v)
|
||||
}
|
||||
|
||||
// Tx performs a duplex transmission to write w to the SPI device
|
||||
// and read len(r) bytes to r.
|
||||
// User should not mutate the w and r until this call returns.
|
||||
func (d *Device) Tx(w, r []byte) error {
|
||||
// TODO(jbd): Allow nil w.
|
||||
return d.conn.Tx(w, r)
|
||||
}
|
||||
|
||||
// Open opens a device with the specified bus and chip select
|
||||
// by using the given driver. If a nil driver is provided,
|
||||
// the default driver (devfs) is used.
|
||||
|
||||
func Open(o driver.Opener) (*Device, error) {
|
||||
conn, err := o.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Device{conn: conn}, nil
|
||||
}
|
||||
|
||||
// Close closes the SPI device and releases the related resources.
|
||||
func (d *Device) Close() error {
|
||||
return d.conn.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user