mirror of https://github.com/periph/devices
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.
206 lines
4.5 KiB
Go
206 lines
4.5 KiB
Go
// Copyright 2022 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 file is largely a copy of mcp23xxx/pins.go, but with a reduced feature
|
|
// set for controlling the chips.
|
|
|
|
package tca95xx
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"periph.io/x/conn/v3"
|
|
"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 tca95xx 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
|
|
input registerCache // input at the pin
|
|
output registerCache // output control, or flipflop state if read
|
|
iodir registerCache // direction
|
|
ipol registerCache // polarity setting
|
|
}
|
|
|
|
func (p *port) pins(count int) []Pin {
|
|
result := make([]Pin, count)
|
|
var i uint8
|
|
for i = 0; i < uint8(count); i++ {
|
|
result[i] = &portpin{
|
|
port: p,
|
|
pinbit: i,
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Tx takes bytes to either read or write. Only half duplex is supported so it
|
|
// is an error to pass 2 buffers at once. The bytes are written or read from
|
|
// the same connection sequentially.
|
|
func (p *port) Tx(w, r []byte) (err error) {
|
|
send := len(w)
|
|
get := len(r)
|
|
switch {
|
|
case send > 0 && get > 0:
|
|
return fmt.Errorf("tca95xx: only conn.Half duplex is supported")
|
|
case send > 0:
|
|
for i := 0; i < send; i++ {
|
|
err = p.output.writeValue(w[i], false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
case get > 0:
|
|
var in uint8
|
|
for i := 0; i < get; i++ {
|
|
in, err = p.input.readValue(false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r[i] = in
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Duplex returns that this is a half duplex connection.
|
|
func (p *port) Duplex() conn.Duplex {
|
|
return conn.Half
|
|
}
|
|
|
|
// String provides the name of this connection.
|
|
func (p *port) String() string {
|
|
return p.name
|
|
}
|
|
|
|
type portpin struct {
|
|
port *port
|
|
pinbit uint8
|
|
}
|
|
|
|
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 pullup
|
|
switch pull {
|
|
case gpio.PullDown:
|
|
// pull down is not supported by any device
|
|
return errors.New("tca95xx: PullDown is not supported")
|
|
case gpio.PullUp:
|
|
return errors.New("tca95xx: PullUp is not supported")
|
|
case gpio.Float, gpio.PullNoChange:
|
|
// Do nothing, supported.
|
|
}
|
|
|
|
// Interrupts are not via I2C bus, so supporting them is less than
|
|
// ideal.
|
|
if edge != gpio.NoEdge {
|
|
return errors.New("tca95xx: edge detection not supported")
|
|
}
|
|
|
|
// Set pin to input
|
|
return p.port.iodir.getAndSetBit(p.pinbit, true, true)
|
|
}
|
|
|
|
func (p *portpin) Read() gpio.Level {
|
|
v, _ := p.port.input.getBit(p.pinbit, false)
|
|
if v {
|
|
return gpio.High
|
|
}
|
|
return gpio.Low
|
|
}
|
|
|
|
func (p *portpin) WaitForEdge(timeout time.Duration) bool {
|
|
return false
|
|
}
|
|
|
|
func (p *portpin) Pull() gpio.Pull {
|
|
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.output.getAndSetBit(p.pinbit, l == gpio.High, true)
|
|
}
|
|
|
|
func (p *portpin) PWM(duty gpio.Duty, f physic.Frequency) error {
|
|
return errors.New("tca95xx: 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("tca95xx: 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}
|