You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
devices/mcp23xxx/pins.go

198 lines
4.1 KiB
Go

// Copyright 2020 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 mcp23xxx
import (
"errors"
"strconv"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/pin"
)
// Pin extends gpio.PinIO interface with features supported by MCP23xxx devices.
type Pin interface {
gpio.PinIO
// SetPolarityInverted if set to true, GPIO register bit reflects the same logic state of the input pin.
SetPolarityInverted(p bool) error
// IsPolarityInverted returns true if the value of the input pin reflects inverted logic state.
IsPolarityInverted() (bool, error)
}
type port struct {
name string
// GPIO basic registers
iodir registerCache
gpio registerCache
olat registerCache
// polarity setting
ipol registerCache
// pull-up control register
// Not present in all devices
gppu registerCache
supportPullup bool
// interrupt handling registers
supportInterrupt bool
gpinten registerCache
intcon registerCache
intf registerCache
intcap registerCache
}
type portpin struct {
port *port
pinbit uint8
}
func (p *port) pins() []Pin {
result := make([]Pin, 8)
var i uint8
for i = 0; i < 8; i++ {
result[i] = &portpin{
port: p,
pinbit: i,
}
}
return result
}
func (p *portpin) String() string {
return p.Name()
}
func (p *portpin) Halt() error {
// To halt all drive, set to high-impedance input
return p.In(gpio.Float, gpio.NoEdge)
}
func (p *portpin) Name() string {
return p.port.name + "_" + strconv.Itoa(int(p.pinbit))
}
func (p *portpin) Number() int {
return int(p.pinbit)
}
func (p *portpin) Function() string {
return string(p.Func())
}
func (p *portpin) In(pull gpio.Pull, edge gpio.Edge) error {
// Set pin to input
err := p.port.iodir.getAndSetBit(p.pinbit, true, true)
if err != nil {
return err
}
// Set pullup
switch pull {
case gpio.PullNoChange:
// don't check, don't change
case gpio.PullDown:
// pull down is not supported by any device
return errors.New("MCP23xxx: PullDown is not supported")
case gpio.PullUp:
if !p.port.supportPullup {
return errors.New("MCP23xxx: PullUp is not supported by this device")
}
err = p.port.gppu.getAndSetBit(p.pinbit, true, true)
if err != nil {
return err
}
case gpio.Float:
if p.port.supportPullup {
err = p.port.gppu.getAndSetBit(p.pinbit, false, true)
if err != nil {
return err
}
}
}
// check edge detection
// TODO interrupt support
return nil
}
func (p *portpin) Read() gpio.Level {
v, _ := p.port.gpio.getBit(p.pinbit, false)
if v {
return gpio.High
}
return gpio.Low
}
func (p *portpin) WaitForEdge(timeout time.Duration) bool {
// TODO interrupt handling
return false
}
func (p *portpin) Pull() gpio.Pull {
if !p.port.supportPullup {
return gpio.Float
}
v, err := p.port.gppu.getBit(p.pinbit, true)
if err != nil {
return gpio.PullNoChange
}
if v {
return gpio.PullUp
}
return gpio.Float
}
func (p *portpin) DefaultPull() gpio.Pull {
return gpio.Float
}
func (p *portpin) Out(l gpio.Level) error {
err := p.port.iodir.getAndSetBit(p.pinbit, false, true)
if err != nil {
return err
}
return p.port.olat.getAndSetBit(p.pinbit, l == gpio.High, true)
}
func (p *portpin) PWM(duty gpio.Duty, f physic.Frequency) error {
return errors.New("MCP23xxx: PWM is not supported")
}
func (p *portpin) Func() pin.Func {
v, _ := p.port.iodir.getBit(p.pinbit, true)
if v {
return gpio.IN
}
return gpio.OUT
}
func (p *portpin) SupportedFuncs() []pin.Func {
return supportedFuncs[:]
}
func (p *portpin) SetFunc(f pin.Func) error {
var v bool
switch f {
case gpio.IN:
v = true
case gpio.OUT:
v = false
default:
return errors.New("MCP23xxx: Function not supported: " + string(f))
}
return p.port.iodir.getAndSetBit(p.pinbit, v, true)
}
func (p *portpin) SetPolarityInverted(pol bool) error {
return p.port.ipol.getAndSetBit(p.pinbit, pol, true)
}
func (p *portpin) IsPolarityInverted() (bool, error) {
return p.port.ipol.getBit(p.pinbit, true)
}
var supportedFuncs = [...]pin.Func{gpio.IN, gpio.OUT}