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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user