mirror of https://github.com/periph/devices
parent
eb90d53534
commit
7555373ca1
@ -0,0 +1,48 @@
|
||||
// Copyright 2025 The Periph Authors. All rights reserved.
|
||||
// Use of this source code is governed under the Apache License, Version 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package pcf857x_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"periph.io/x/conn/v3/gpio"
|
||||
"periph.io/x/conn/v3/i2c/i2creg"
|
||||
"periph.io/x/devices/v3/pcf857x"
|
||||
"periph.io/x/host/v3"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
// Make sure periph is initialized.
|
||||
if _, err := host.Init(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Open default I²C bus.
|
||||
bus, err := i2creg.Open("")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open I²C: %v", err)
|
||||
}
|
||||
defer bus.Close()
|
||||
|
||||
// Create a new I2C IO extender
|
||||
extender, err := pcf857x.New(bus, pcf857x.DefaultAddress, pcf857x.PCF8574)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
for _, pin := range extender.Pins {
|
||||
err = pin.In(gpio.Float, gpio.NoEdge)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
level := pin.Read()
|
||||
fmt.Printf("%s\t%s\n", pin.Name(), level.String())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,320 @@
|
||||
// Copyright 2025 The Periph Authors. All rights reserved.
|
||||
// Use of this source code is governed under the Apache License, Version 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// This package provides a driver for the TI/NXP PCF857X I2C I/O Expander. These
|
||||
// devices provide 8 pins (PCF8574) or 16 pins (PCF8575) of
|
||||
// "quasi-bidirectional" input/output. This device is commonly used in LCD
|
||||
// backpacks, particularly those sold as LCD2004, LCD1602.
|
||||
//
|
||||
// The PCF8575 is a 16-pin device that is functionally identical to the PCF8574.
|
||||
// When communicating with the PCF8575 reads and writes are 2 bytes wide, while
|
||||
// they're one byte wide with the PCF85754
|
||||
//
|
||||
// # Datasheet
|
||||
//
|
||||
// https://www.ti.com/lit/ds/symlink/pcf8574.pdf
|
||||
//
|
||||
// A good description of the I2C LCD backpack usage can be found here:
|
||||
//
|
||||
// https://www.handsontec.com/dataspecs/I2C_2004_LCD.pdf
|
||||
//
|
||||
// Adafruit also sells a breakout board with these chips. See here:
|
||||
//
|
||||
// https://www.adafruit.com/product/5611
|
||||
//
|
||||
// # Notes
|
||||
//
|
||||
// This device is very simple and doesn't have functionality that similar
|
||||
// devices do. Specifically, GPIO Read() consists of writing a High out a pin,
|
||||
// and then reading it to see if it is still high, or if it has transitioned to
|
||||
// low.
|
||||
//
|
||||
// Setting a pin to Low activates an Open Drain to ground.
|
||||
//
|
||||
// You cannot detect edge change on a specific pin. There is an interrupt pin
|
||||
// that can be used to detect a change on the GPIO pins, but it doesn't tell you
|
||||
// which pin changed.
|
||||
//
|
||||
// This chip doesn't implement normal i2c register architectures. You write 8 or
|
||||
// 16 bits out, and that sets the corresponding pins, or you read 8/16 bits and
|
||||
// get the state of the pins.
|
||||
package pcf857x
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"periph.io/x/conn/v3/gpio"
|
||||
"periph.io/x/conn/v3/gpio/gpioreg"
|
||||
"periph.io/x/conn/v3/i2c"
|
||||
"periph.io/x/conn/v3/pin"
|
||||
)
|
||||
|
||||
// Variant represents the actual chip model.
|
||||
type Variant string
|
||||
|
||||
const (
|
||||
PCF8574 Variant = "PCF8574"
|
||||
PCF8575 Variant = "PCF8575"
|
||||
|
||||
DefaultAddress uint16 = 0x20
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotImplmented error = errors.New("pcf857x: not implemented")
|
||||
)
|
||||
|
||||
// Dev is representation of a PCF857x device.
|
||||
type Dev struct {
|
||||
// The pins exposed by the device. For PCF8574, this will be 8 pins, and
|
||||
// 16 pins for the PCF8575
|
||||
Pins []gpio.PinIO
|
||||
mask gpio.GPIOValue
|
||||
width int
|
||||
chipType Variant
|
||||
|
||||
mu sync.Mutex
|
||||
d *i2c.Dev
|
||||
value gpio.GPIOValue
|
||||
groups []Group
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
pins []pcfPin
|
||||
dev *Dev
|
||||
}
|
||||
|
||||
// New creates a new PCF857x io expander and returns it. chip should be one of
|
||||
// the Variant constants above.
|
||||
func New(bus i2c.Bus, address uint16, chip Variant) (*Dev, error) {
|
||||
dev := &Dev{d: &i2c.Dev{Bus: bus, Addr: address},
|
||||
chipType: chip}
|
||||
if chip == PCF8574 {
|
||||
dev.width = 8
|
||||
} else {
|
||||
dev.width = 16
|
||||
}
|
||||
dev.mask = gpio.GPIOValue((1 << dev.width) - 1)
|
||||
dev.Pins = make([]gpio.PinIO, dev.width)
|
||||
sDev := dev.String()
|
||||
for ix := range dev.width {
|
||||
name := fmt.Sprintf("%s_GPIO%d", sDev, ix)
|
||||
dev.Pins[ix] = &pcfPin{dev: dev, number: ix, name: name}
|
||||
_ = gpioreg.Register(dev.Pins[ix])
|
||||
}
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
// Group returns a GPIO Group comprised of the specified pin numbers. A
|
||||
// gpio.Group allows you to perform writes to multiple pins in one operation.
|
||||
func (dev *Dev) Group(pinNumbers ...int) (gpio.Group, error) {
|
||||
dev.mu.Lock()
|
||||
defer dev.mu.Unlock()
|
||||
gr := Group{dev: dev, pins: make([]pcfPin, len(pinNumbers))}
|
||||
for ix, pinNumber := range pinNumbers {
|
||||
if p, ok := dev.Pins[pinNumber].(*pcfPin); ok {
|
||||
gr.pins[ix] = *p
|
||||
}
|
||||
}
|
||||
dev.groups = append(dev.groups, gr)
|
||||
return &gr, nil
|
||||
}
|
||||
|
||||
// Halt shuts down the device, and frees any pin groups.
|
||||
func (dev *Dev) Halt() error {
|
||||
dev.mu.Lock()
|
||||
defer dev.mu.Unlock()
|
||||
for _, gr := range dev.groups {
|
||||
_ = gr.Halt()
|
||||
}
|
||||
dev.groups = make([]Group, 0)
|
||||
dev.Pins = make([]gpio.PinIO, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// read performs the low level i2c read operation from the device.
|
||||
func (dev *Dev) read(mask gpio.GPIOValue) (gpio.GPIOValue, error) {
|
||||
|
||||
// Before you can read a pin, you must have set it to high. If nothing
|
||||
// pulls that down, then it's high. If it's pulled down, it's low.
|
||||
err := dev.write(mask, mask)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("pcf857x: %w", err)
|
||||
}
|
||||
|
||||
dev.mu.Lock()
|
||||
defer dev.mu.Unlock()
|
||||
byteCount := 1
|
||||
if dev.width > 8 {
|
||||
byteCount += 1
|
||||
}
|
||||
|
||||
r := make([]byte, byteCount)
|
||||
err = dev.d.Tx(nil, r)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("pcf857x: %w", err)
|
||||
}
|
||||
result := gpio.GPIOValue(r[0])
|
||||
if byteCount > 1 {
|
||||
result |= gpio.GPIOValue(r[1]) << 8
|
||||
|
||||
}
|
||||
// turn off the bits we just read so that the next time through, we force
|
||||
// the write high on them.
|
||||
dev.value = result
|
||||
result &= mask
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// write performs the low-level write to the device. If the resulting value of
|
||||
// the device is unchanged, the write is skipped.
|
||||
func (dev *Dev) write(value, mask gpio.GPIOValue) error {
|
||||
dev.mu.Lock()
|
||||
defer dev.mu.Unlock()
|
||||
wrValue := dev.value & (dev.mask ^ mask)
|
||||
wrValue |= (value & mask)
|
||||
if dev.value == wrValue {
|
||||
return nil
|
||||
}
|
||||
byteCount := 1
|
||||
if dev.width > 8 {
|
||||
byteCount += 1
|
||||
}
|
||||
w := make([]byte, byteCount)
|
||||
for ix := range byteCount {
|
||||
w[ix] = byte(wrValue >> (ix * 8))
|
||||
}
|
||||
err := dev.d.Tx(w, nil)
|
||||
if err == nil {
|
||||
dev.value = wrValue
|
||||
} else {
|
||||
err = fmt.Errorf("pcf857x: %w", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (dev *Dev) String() string {
|
||||
return fmt.Sprintf("%s_%x", dev.chipType, dev.d.Addr)
|
||||
}
|
||||
|
||||
// Pins returns the set of pins that make up this group.
|
||||
func (gr *Group) Pins() []pin.Pin {
|
||||
pins := make([]pin.Pin, len(gr.pins))
|
||||
for ix := range len(gr.pins) {
|
||||
pins[ix] = &gr.pins[ix]
|
||||
}
|
||||
return pins
|
||||
}
|
||||
|
||||
// This converts a mask for a group operation into a mask suitable for writing
|
||||
// to the device.
|
||||
func (gr *Group) groupMaskToDevMask(mask gpio.GPIOValue) gpio.GPIOValue {
|
||||
m := gpio.GPIOValue(0)
|
||||
for ix := range len(gr.pins) {
|
||||
currentBit := gpio.GPIOValue(1 << ix)
|
||||
if (mask & currentBit) == currentBit {
|
||||
pinBit := gpio.GPIOValue(1) << gr.pins[ix].number
|
||||
m |= pinBit
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Return the GPIO pin by offset within the group.
|
||||
func (gr *Group) ByOffset(offset int) pin.Pin {
|
||||
return &gr.pins[offset]
|
||||
}
|
||||
|
||||
// Return the GPIO pin by name.
|
||||
func (gr *Group) ByName(name string) pin.Pin {
|
||||
for ix := range len(gr.pins) {
|
||||
if gr.pins[ix].name == name {
|
||||
return &gr.pins[ix]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return the GPIO pin by it's pin number on the device.
|
||||
func (gr *Group) ByNumber(number int) pin.Pin {
|
||||
for ix := range len(gr.pins) {
|
||||
if gr.pins[ix].number == number {
|
||||
return &gr.pins[ix]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out writes the specified value to the device. Only pins identified by mask
|
||||
// are modified.
|
||||
func (gr *Group) Out(value, mask gpio.GPIOValue) error {
|
||||
if mask == 0 {
|
||||
mask = (1 << len(gr.pins)) - 1
|
||||
}
|
||||
wrMask := gr.groupMaskToDevMask(mask)
|
||||
wr := gpio.GPIOValue(0)
|
||||
for ix, pin := range gr.pins {
|
||||
if (value & gpio.GPIOValue(1<<ix)) > 0 {
|
||||
wr |= 1 << pin.number
|
||||
}
|
||||
}
|
||||
return gr.dev.write(wr, wrMask)
|
||||
}
|
||||
|
||||
// Read returns the current values of the pins within the group identified by
|
||||
// mask.
|
||||
func (gr *Group) Read(mask gpio.GPIOValue) (gpio.GPIOValue, error) {
|
||||
if mask == 0 {
|
||||
mask = (1 << len(gr.pins)) - 1
|
||||
}
|
||||
devMask := gr.groupMaskToDevMask(mask)
|
||||
|
||||
v, err := gr.dev.read(devMask)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("pcf857x: %w", err)
|
||||
}
|
||||
|
||||
// Now, convert it back to a group value.
|
||||
result := gpio.GPIOValue(0)
|
||||
for ix, pin := range gr.pins {
|
||||
currentBit := gpio.GPIOValue(1 << ix)
|
||||
if (mask & currentBit) == currentBit {
|
||||
if (v & gpio.GPIOValue(1<<pin.number)) > 0 {
|
||||
result |= currentBit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// This chip does not support waiting for edge on either a pin or a group. There
|
||||
// is an interrupt pin, but you can't set a mask of pins that will trigger it. To
|
||||
// do that, you connect a GPIO pin from the host device that supports WaitForEdge
|
||||
// to monitor the INTR pin.
|
||||
func (gr *Group) WaitForEdge(timeout time.Duration) (number int, edge gpio.Edge, err error) {
|
||||
// TODO: Implement wait for edge in the same way that it is for mcp23008
|
||||
return 0, gpio.NoEdge, ErrNotImplmented
|
||||
}
|
||||
|
||||
// Halt stops the pin group. It cannot be used after this call.
|
||||
func (gr *Group) Halt() error {
|
||||
gr.pins = make([]pcfPin, 0)
|
||||
gr.dev = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gr *Group) String() string {
|
||||
s := gr.dev.String() + "[ "
|
||||
for ix := range len(gr.pins) {
|
||||
s += fmt.Sprintf("%d ", gr.pins[ix].Number())
|
||||
}
|
||||
s += "]"
|
||||
return s
|
||||
}
|
||||
|
||||
var _ gpio.Group = &Group{}
|
||||
@ -0,0 +1,216 @@
|
||||
// Copyright 2025 The Periph Authors. All rights reserved.
|
||||
// Use of this source code is governed under the Apache License, Version 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
//
|
||||
// This test assumes you have a PCF8575 and that the data pins are jumpered
|
||||
//
|
||||
// 0 => 8
|
||||
// 1 => 9
|
||||
// ...
|
||||
// 7 => 15
|
||||
|
||||
package pcf857x
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"periph.io/x/conn/v3/gpio"
|
||||
"periph.io/x/conn/v3/gpio/gpioreg"
|
||||
"periph.io/x/conn/v3/i2c/i2ctest"
|
||||
)
|
||||
|
||||
func getDev(recordingName string, t *testing.T) (*Dev, error) {
|
||||
// Create a new I2C IO extender
|
||||
bus := i2ctest.Playback{Ops: recordingData[recordingName]}
|
||||
extender, err := New(&bus, DefaultAddress, PCF8575)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return extender, err
|
||||
}
|
||||
|
||||
// Test basic dev and pin functions.
|
||||
func TestBasic(t *testing.T) {
|
||||
dev, err := getDev(t.Name(), t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t.Logf("dev=%#v", dev)
|
||||
pin := dev.Pins[1]
|
||||
t.Logf("pin=%#v", pin)
|
||||
|
||||
s := dev.String()
|
||||
if len(s) == 0 {
|
||||
t.Error("String() failure")
|
||||
} //
|
||||
|
||||
if len(dev.Pins) != 16 {
|
||||
t.Errorf("expected 16 GPIO pins. Found %d", len(dev.Pins))
|
||||
}
|
||||
|
||||
e := pin.PWM(10, 10)
|
||||
if !errors.Is(e, ErrNotImplmented) {
|
||||
t.Errorf("PWM() expected ErrNotImplemented. Received %#v", e)
|
||||
}
|
||||
if pin.Halt() != nil {
|
||||
t.Error("expected nil on pin.Halt()")
|
||||
}
|
||||
|
||||
if pin.Name() != pin.String() {
|
||||
t.Error("pin.Name()!=pin.String()")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(pin.Name(), dev.String()) {
|
||||
t.Errorf("Expected pin.Name()=%s to start with dev.String()=%s", pin.Name(), dev.String())
|
||||
}
|
||||
|
||||
err = dev.Halt()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the pins are registered in gpioreg as expected.
|
||||
func TestGPIOReg(t *testing.T) {
|
||||
dev, err := getDev(t.Name(), t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for ix := range dev.width {
|
||||
p := dev.Pins[ix]
|
||||
if p.Number() != ix {
|
||||
t.Errorf("pin.Number() does not match ordinal position %d! Found %d", ix, p.Number())
|
||||
}
|
||||
pReg := gpioreg.ByName(p.Name())
|
||||
if pReg == nil {
|
||||
t.Errorf("pin %s not found in gpioreg", p.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This test goes through the pins from 0-7, and writes to them and then reads
|
||||
// the value on pin+8 and verifies it's correct. Then, it reverses direction and
|
||||
// writes to pin[8] and reads from pin[0].
|
||||
func TestPinsSequentially(t *testing.T) {
|
||||
dev, err := getDev(t.Name(), t)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
limit := dev.width >> 1
|
||||
for ixOuter := range limit {
|
||||
// Iterate over the lower 8 pins
|
||||
for ixInner := range limit {
|
||||
// Sequentially, set each pin to High if it's not the value of ix
|
||||
p := dev.Pins[ixInner]
|
||||
pRead := dev.Pins[ixInner+limit]
|
||||
for direction := range 2 {
|
||||
writeLevel := gpio.Level(ixInner != ixOuter)
|
||||
err = p.Out(writeLevel)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
readVal := pRead.Read()
|
||||
if readVal != writeLevel {
|
||||
t.Errorf("wrote %t to pin[%d]. Expected same on pin[%d], found %t",
|
||||
writeLevel,
|
||||
p.Number(),
|
||||
pRead.Number(),
|
||||
readVal)
|
||||
}
|
||||
if direction == 0 {
|
||||
// swap the direction so we're now going pin[8] => pin[0] and stay in
|
||||
// the loop to repeat the test.
|
||||
x := pRead
|
||||
pRead = p
|
||||
p = x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This tests the group functionality.
|
||||
func TestGroup(t *testing.T) {
|
||||
dev, err := getDev(t.Name(), t)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() { _ = dev.Halt() }()
|
||||
|
||||
set1 := make([]int, dev.width>>1)
|
||||
set2 := make([]int, dev.width>>1)
|
||||
for ix := range len(set1) {
|
||||
set1[ix] = ix
|
||||
set2[ix] = ix + len(set1)
|
||||
}
|
||||
gr1, err := dev.Group(set1...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
gr2, err := dev.Group(set2...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Test the basic group functionality. Note that for group1, pinOffset==pin.Number, but
|
||||
// for group2, pinOffset!=pin.Number
|
||||
grTest := gr1
|
||||
for range 2 {
|
||||
for pinNumber, pin := range grTest.Pins() {
|
||||
x := grTest.ByNumber(pin.Number())
|
||||
if x == nil {
|
||||
t.Errorf("group.ByNumber() returned nil for pin %d", pin.Number())
|
||||
}
|
||||
x = grTest.ByOffset(pinNumber)
|
||||
if x == nil {
|
||||
t.Errorf("group.ByOffset returned nil for pin number %d", pinNumber)
|
||||
} else {
|
||||
if x.Number() != pin.Number() {
|
||||
t.Errorf("group.ByOffset() didn't return the expected pin. Expected %d, found %d", pin.Number(), x.Number())
|
||||
}
|
||||
}
|
||||
x = grTest.ByName(pin.Name())
|
||||
if x == nil || x.Name() != pin.Name() {
|
||||
t.Error("group.ByName() didn't find a pin or returned the wrong pin!")
|
||||
}
|
||||
}
|
||||
grTest = gr2
|
||||
}
|
||||
if len(gr1.String()) == 0 {
|
||||
t.Error("group.String() didn't return a value")
|
||||
}
|
||||
// Test the read/write functionality.
|
||||
limit := (1 << len(set1))
|
||||
var read gpio.GPIOValue
|
||||
for groupNumber := range 2 {
|
||||
for val := range limit {
|
||||
err = gr1.Out(gpio.GPIOValue(val), 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
read, err = gr2.Read(0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if read != gpio.GPIOValue(val) {
|
||||
t.Errorf("Error writing/reading groups. Wrote %d on write group %s, read %d on read group%s", val, gr1, read, gr2)
|
||||
}
|
||||
}
|
||||
if groupNumber == 0 {
|
||||
x := gr1
|
||||
gr1 = gr2
|
||||
gr2 = x
|
||||
}
|
||||
}
|
||||
err = gr1.Halt()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
err = gr2.Halt()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,92 @@
|
||||
// Copyright 2025 The Periph Authors. All rights reserved.
|
||||
// Use of this source code is governed under the Apache License, Version 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package pcf857x
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"periph.io/x/conn/v3/gpio"
|
||||
"periph.io/x/conn/v3/physic"
|
||||
)
|
||||
|
||||
type pcfPin struct {
|
||||
dev *Dev
|
||||
number int
|
||||
name string
|
||||
}
|
||||
|
||||
func (pin *pcfPin) DefaultPull() gpio.Pull {
|
||||
return gpio.Float
|
||||
}
|
||||
|
||||
func (pin *pcfPin) Function() string {
|
||||
return "Out"
|
||||
}
|
||||
|
||||
func (pcf *pcfPin) Halt() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pin *pcfPin) In(pull gpio.Pull, edge gpio.Edge) error {
|
||||
// To use a pin for input, you must write a High to that pin, and then
|
||||
// perform the read. The chip doesn't natively support pullup/pulldown.
|
||||
//
|
||||
// Refer to the datasheet for more information.
|
||||
v := gpio.GPIOValue(1 << pin.number)
|
||||
return pin.dev.write(v, v)
|
||||
}
|
||||
|
||||
func (pin *pcfPin) Name() string {
|
||||
return pin.name
|
||||
}
|
||||
|
||||
func (pin *pcfPin) Number() int {
|
||||
return pin.number
|
||||
}
|
||||
|
||||
func (pin *pcfPin) Out(l gpio.Level) error {
|
||||
value := gpio.GPIOValue(0)
|
||||
mask := gpio.GPIOValue(1 << pin.number)
|
||||
if l {
|
||||
value = mask
|
||||
}
|
||||
return pin.dev.write(value, mask)
|
||||
}
|
||||
|
||||
func (pin *pcfPin) Pull() gpio.Pull {
|
||||
return gpio.Float
|
||||
}
|
||||
|
||||
func (pin *pcfPin) Read() gpio.Level {
|
||||
|
||||
result := gpio.Low
|
||||
mask := gpio.GPIOValue(1 << pin.number)
|
||||
|
||||
value, err := pin.dev.read(mask)
|
||||
if err == nil {
|
||||
result = (value & mask) == mask
|
||||
} else {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (pin *pcfPin) PWM(duty gpio.Duty, f physic.Frequency) error {
|
||||
return ErrNotImplmented
|
||||
}
|
||||
|
||||
func (pin *pcfPin) String() string {
|
||||
return pin.name
|
||||
}
|
||||
|
||||
// This device has an interrupt pin that can detect a change on the GPIO lines,
|
||||
// however it doesn't let you detect a change on a specific pin.
|
||||
func (pin *pcfPin) WaitForEdge(timeout time.Duration) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var _ gpio.PinIO = &pcfPin{}
|
||||
Loading…
Reference in New Issue