2023-04-22 08:37:23 +00:00
|
|
|
// SPDX-FileCopyrightText: 2019 Kent Gibson <warthog618@gmail.com>
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2024-06-15 13:58:47 +00:00
|
|
|
package gpiocdev
|
2023-04-22 08:37:23 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
2024-06-15 13:58:47 +00:00
|
|
|
"github.com/warthog618/go-gpiocdev/uapi"
|
2023-04-22 08:37:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ChipOption defines the interface required to provide a Chip option.
|
|
|
|
type ChipOption interface {
|
|
|
|
applyChipOption(*ChipOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChipOptions contains the options for a Chip.
|
|
|
|
type ChipOptions struct {
|
|
|
|
consumer string
|
|
|
|
config LineConfig
|
|
|
|
abi int
|
|
|
|
eh EventHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConsumerOption defines the consumer label for a line.
|
|
|
|
type ConsumerOption string
|
|
|
|
|
|
|
|
// WithConsumer provides the consumer label for the line.
|
|
|
|
//
|
|
|
|
// When applied to a chip it provides the default consumer label for all lines
|
|
|
|
// requested by the chip.
|
|
|
|
func WithConsumer(consumer string) ConsumerOption {
|
|
|
|
return ConsumerOption(consumer)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o ConsumerOption) applyChipOption(c *ChipOptions) {
|
|
|
|
c.consumer = string(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o ConsumerOption) applyLineReqOption(l *lineReqOptions) {
|
|
|
|
l.consumer = string(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
// LineReqOption defines the interface required to provide an option for Line and
|
|
|
|
// Lines as part of a line request.
|
|
|
|
type LineReqOption interface {
|
|
|
|
applyLineReqOption(*lineReqOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
// LineConfigOption defines the interface required to update an option for
|
|
|
|
// Line and Lines.
|
|
|
|
type LineConfigOption interface {
|
|
|
|
applyLineConfigOption(*lineConfigOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SubsetLineConfigOption defines the interface required to update an option for a
|
|
|
|
// subset of requested lines.
|
|
|
|
type SubsetLineConfigOption interface {
|
|
|
|
applySubsetLineConfigOption([]int, *lineConfigOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
// lineReqOptions contains the options for a Line(s) request.
|
|
|
|
type lineReqOptions struct {
|
|
|
|
lineConfigOptions
|
|
|
|
consumer string
|
|
|
|
abi int
|
|
|
|
eh EventHandler
|
|
|
|
eventBufferSize int
|
|
|
|
}
|
|
|
|
|
|
|
|
// lineConfigOptions contains the configuration options for a Line(s) reconfigure.
|
|
|
|
type lineConfigOptions struct {
|
|
|
|
offsets []int
|
|
|
|
values map[int]int
|
|
|
|
defCfg LineConfig
|
|
|
|
lineCfg map[int]*LineConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lco *lineConfigOptions) lineConfig(offset int) *LineConfig {
|
|
|
|
if lco.lineCfg == nil {
|
|
|
|
lco.lineCfg = map[int]*LineConfig{}
|
|
|
|
}
|
|
|
|
lc := lco.lineCfg[offset]
|
|
|
|
if lc == nil {
|
|
|
|
tlc := lco.defCfg
|
|
|
|
lc = &tlc
|
|
|
|
lco.lineCfg[offset] = lc
|
|
|
|
}
|
|
|
|
return lc
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lco lineConfigOptions) outputValues() uapi.OutputValues {
|
|
|
|
ov := uapi.LineBitmap(0)
|
|
|
|
for idx, val := range lco.offsets {
|
|
|
|
ov = ov.Set(idx, lco.values[val])
|
|
|
|
}
|
|
|
|
return uapi.OutputValues(ov)
|
|
|
|
}
|
|
|
|
|
|
|
|
type lineConfigAttributes []uapi.LineConfigAttribute
|
|
|
|
|
|
|
|
func (lca lineConfigAttributes) append(attr uapi.LineAttribute, mask uapi.LineBitmap) lineConfigAttributes {
|
|
|
|
for idx, cae := range lca {
|
|
|
|
if cae.Attr.ID == attr.ID {
|
|
|
|
lca[idx].Mask &^= mask
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for idx, cae := range lca {
|
|
|
|
if cae.Attr == attr {
|
|
|
|
lca[idx].Mask |= mask
|
|
|
|
return lca
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return append(lca, uapi.LineConfigAttribute{Attr: attr, Mask: mask})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lco lineConfigOptions) toULineConfig() (ulc uapi.LineConfig, err error) {
|
|
|
|
|
|
|
|
mask := uapi.NewLineBitMask(len(lco.offsets))
|
|
|
|
cfgAttrs := lineConfigAttributes{
|
|
|
|
// first cfg slot reserved for default flags
|
|
|
|
uapi.LineConfigAttribute{Attr: uapi.LineFlagV2(0).Encode(), Mask: mask},
|
|
|
|
}
|
|
|
|
attrs := lco.defCfg.toLineAttributes()
|
|
|
|
for _, attr := range attrs {
|
|
|
|
if attr.ID == uapi.LineAttributeIDFlags {
|
|
|
|
cfgAttrs[0].Attr = attr
|
|
|
|
} else {
|
|
|
|
cfgAttrs = cfgAttrs.append(attr, mask)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var outputMask uapi.LineBitmap
|
|
|
|
if lco.defCfg.Direction == LineDirectionOutput {
|
|
|
|
outputMask = mask
|
|
|
|
}
|
|
|
|
|
|
|
|
for idx, offset := range lco.offsets {
|
|
|
|
cfg := lco.lineCfg[offset]
|
|
|
|
if cfg == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
mask = uapi.LineBitmap(1) << uint(idx)
|
|
|
|
attrs = cfg.toLineAttributes()
|
|
|
|
for _, attr := range attrs {
|
|
|
|
cfgAttrs = cfgAttrs.append(attr, mask)
|
|
|
|
}
|
|
|
|
if cfg.Direction == LineDirectionOutput {
|
|
|
|
outputMask |= mask
|
|
|
|
} else {
|
|
|
|
outputMask &^= mask
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var defFlags uapi.LineFlagV2
|
|
|
|
defFlags.Decode(cfgAttrs[0].Attr)
|
|
|
|
// replace default flags in slot 0 with outputValues
|
|
|
|
cfgAttrs[0].Attr = lco.outputValues().Encode()
|
|
|
|
cfgAttrs[0].Mask = outputMask
|
|
|
|
|
|
|
|
// filter mask==0 entries
|
|
|
|
loopAttrs := cfgAttrs
|
|
|
|
cfgAttrs = cfgAttrs[:0]
|
|
|
|
for _, attr := range loopAttrs {
|
|
|
|
if attr.Mask != 0 {
|
|
|
|
cfgAttrs = append(cfgAttrs, attr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(cfgAttrs) > 10 {
|
|
|
|
err = ErrConfigOverflow
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ulc.Flags = defFlags
|
|
|
|
ulc.NumAttrs = uint32(len(cfgAttrs))
|
|
|
|
copy(ulc.Attrs[:], cfgAttrs)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// EventHandler is a receiver for line events.
|
|
|
|
type EventHandler func(LineEvent)
|
|
|
|
|
|
|
|
// AsIsOption indicates the line direction should be left as is.
|
|
|
|
type AsIsOption int
|
|
|
|
|
|
|
|
// AsIs indicates that a line be requested as neither an input or output.
|
|
|
|
//
|
|
|
|
// That is its direction is left as is. This option overrides and clears any
|
|
|
|
// previous Input or Output options.
|
|
|
|
const AsIs = AsIsOption(0)
|
|
|
|
|
|
|
|
func (o AsIsOption) applyLineReqOption(l *lineReqOptions) {
|
|
|
|
l.defCfg.Direction = LineDirectionUnknown
|
|
|
|
}
|
|
|
|
|
|
|
|
// InputOption indicates the line direction should be set to an input.
|
|
|
|
type InputOption int
|
|
|
|
|
|
|
|
// AsInput indicates that a line be requested as an input.
|
|
|
|
//
|
|
|
|
// This option overrides and clears any previous Output, OpenDrain, or
|
|
|
|
// OpenSource options.
|
|
|
|
const AsInput = InputOption(0)
|
|
|
|
|
|
|
|
func (o InputOption) applyLineConfig(lc *LineConfig) {
|
|
|
|
lc.Direction = LineDirectionInput
|
|
|
|
lc.Drive = LineDrivePushPull
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o InputOption) applyChipOption(c *ChipOptions) {
|
|
|
|
c.config.Direction = LineDirectionInput
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o InputOption) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
o.applyLineConfigOption(&lro.lineConfigOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o InputOption) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
o.applyLineConfig(&lco.defCfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o InputOption) applySubsetLineConfigOption(offsets []int, l *lineConfigOptions) {
|
|
|
|
for _, offset := range offsets {
|
|
|
|
o.applyLineConfig(l.lineConfig(offset))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// OutputOption indicates the line direction should be set to an output.
|
|
|
|
type OutputOption []int
|
|
|
|
|
|
|
|
// AsOutput indicates that a line or lines be requested as an output.
|
|
|
|
//
|
|
|
|
// The initial active state for the line(s) can optionally be provided.
|
|
|
|
// If fewer values are provided than lines then the remaining lines default to
|
|
|
|
// inactive.
|
|
|
|
//
|
|
|
|
// This option overrides and clears any previous Input, RisingEdge, FallingEdge,
|
|
|
|
// BothEdges, or Debounce options.
|
|
|
|
func AsOutput(values ...int) OutputOption {
|
|
|
|
vv := append([]int(nil), values...)
|
|
|
|
return OutputOption(vv)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o OutputOption) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
o.applyLineConfigOption(&lro.lineConfigOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o OutputOption) applyLineConfig(lc *LineConfig) {
|
|
|
|
lc.Direction = LineDirectionOutput
|
|
|
|
lc.Debounced = false
|
|
|
|
lc.DebouncePeriod = 0
|
|
|
|
lc.EdgeDetection = LineEdgeNone
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o OutputOption) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
o.applyLineConfig(&lco.defCfg)
|
|
|
|
for idx, value := range o {
|
|
|
|
lco.values[lco.offsets[idx]] = value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o OutputOption) applySubsetLineConfigOption(offsets []int, lco *lineConfigOptions) {
|
|
|
|
for idx, offset := range offsets {
|
|
|
|
o.applyLineConfig(lco.lineConfig(offset))
|
|
|
|
lco.values[offset] = o[idx]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// LevelOption determines the line level that is considered active.
|
|
|
|
type LevelOption bool
|
|
|
|
|
|
|
|
func (o LevelOption) applyChipOption(c *ChipOptions) {
|
|
|
|
c.config.ActiveLow = bool(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LevelOption) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
lro.defCfg.ActiveLow = bool(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LevelOption) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
lco.defCfg.ActiveLow = bool(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LevelOption) applySubsetLineConfigOption(offsets []int, lco *lineConfigOptions) {
|
|
|
|
for _, offset := range offsets {
|
|
|
|
lco.lineConfig(offset).ActiveLow = bool(o)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AsActiveLow indicates that a line be considered active when the line level
|
|
|
|
// is low.
|
|
|
|
const AsActiveLow = LevelOption(true)
|
|
|
|
|
|
|
|
// AsActiveHigh indicates that a line be considered active when the line level
|
|
|
|
// is high.
|
|
|
|
//
|
|
|
|
// This is the default active level.
|
|
|
|
const AsActiveHigh = LevelOption(false)
|
|
|
|
|
|
|
|
func (o LineDrive) applyLineConfig(lc *LineConfig) {
|
|
|
|
lc.Drive = o
|
|
|
|
lc.Direction = LineDirectionOutput
|
|
|
|
lc.Debounced = false
|
|
|
|
lc.DebouncePeriod = 0
|
|
|
|
lc.EdgeDetection = LineEdgeNone
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineDrive) applyChipOption(c *ChipOptions) {
|
|
|
|
o.applyLineConfig(&c.config)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineDrive) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
o.applyLineConfig(&lro.defCfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineDrive) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
o.applyLineConfig(&lco.defCfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineDrive) applySubsetLineConfigOption(offsets []int, lco *lineConfigOptions) {
|
|
|
|
for _, offset := range offsets {
|
|
|
|
o.applyLineConfig(lco.lineConfig(offset))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AsOpenDrain indicates that a line be driven low but left floating for high.
|
|
|
|
//
|
|
|
|
// This option sets the Output option and overrides and clears any previous
|
|
|
|
// Input, RisingEdge, FallingEdge, BothEdges, OpenSource, or Debounce options.
|
|
|
|
const AsOpenDrain = LineDriveOpenDrain
|
|
|
|
|
|
|
|
// AsOpenSource indicates that a line be driven high but left floating for low.
|
|
|
|
//
|
|
|
|
// This option sets the Output option and overrides and clears any previous
|
|
|
|
// Input, RisingEdge, FallingEdge, BothEdges, OpenDrain, or Debounce options.
|
|
|
|
const AsOpenSource = LineDriveOpenSource
|
|
|
|
|
|
|
|
// AsPushPull indicates that a line be driven both low and high.
|
|
|
|
//
|
|
|
|
// This option sets the Output option and overrides and clears any previous
|
|
|
|
// Input, RisingEdge, FallingEdge, BothEdges, OpenDrain, OpenSource or Debounce
|
|
|
|
// options.
|
|
|
|
const AsPushPull = LineDrivePushPull
|
|
|
|
|
|
|
|
func (o LineBias) applyChipOption(c *ChipOptions) {
|
|
|
|
c.config.Bias = o
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineBias) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
lro.defCfg.Bias = o
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineBias) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
lco.defCfg.Bias = o
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineBias) applySubsetLineConfigOption(offsets []int, lco *lineConfigOptions) {
|
|
|
|
for _, offset := range offsets {
|
|
|
|
lco.lineConfig(offset).Bias = o
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithBiasAsIs indicates that a line have its internal bias left unchanged.
|
|
|
|
//
|
|
|
|
// This option corresponds to the default bias configuration and its only useful
|
|
|
|
// application is to clear any previous bias option in a chain of LineOptions,
|
|
|
|
// before that configuration is applied.
|
|
|
|
//
|
|
|
|
// Requires Linux v5.5 or later.
|
|
|
|
const WithBiasAsIs = LineBiasUnknown
|
|
|
|
|
|
|
|
// WithBiasDisabled indicates that a line have its internal bias disabled.
|
|
|
|
//
|
|
|
|
// This option overrides and clears any previous bias options.
|
|
|
|
//
|
|
|
|
// Requires Linux v5.5 or later.
|
|
|
|
const WithBiasDisabled = LineBiasDisabled
|
|
|
|
|
|
|
|
// WithPullDown indicates that a line have its internal pull-down enabled.
|
|
|
|
//
|
|
|
|
// This option overrides and clears any previous bias options.
|
|
|
|
//
|
|
|
|
// Requires Linux v5.5 or later.
|
|
|
|
const WithPullDown = LineBiasPullDown
|
|
|
|
|
|
|
|
// WithPullUp indicates that a line have its internal pull-up enabled.
|
|
|
|
//
|
|
|
|
// This option overrides and clears any previous bias options.
|
|
|
|
//
|
|
|
|
// Requires Linux v5.5 or later.
|
|
|
|
const WithPullUp = LineBiasPullUp
|
|
|
|
|
|
|
|
func (o EventHandler) applyChipOption(c *ChipOptions) {
|
|
|
|
c.eh = o
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o EventHandler) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
lro.eh = o
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithEventHandler indicates that a line will generate events when its active
|
|
|
|
// state transitions from high to low.
|
|
|
|
//
|
|
|
|
// Events are forwarded to the provided handler function.
|
|
|
|
//
|
|
|
|
// To maintain event ordering, the event handler is called serially for each
|
|
|
|
// event from the requested lines. To minimize the possiblity of overflowing
|
|
|
|
// the queue of events in the kernel, the event handler should handle or
|
|
|
|
// hand-off the event and return as soon as possible.
|
|
|
|
//
|
|
|
|
// Note that calling Close on the requested line from within the event handler
|
|
|
|
// will result in deadlock, as the Close waits for the event handler to
|
|
|
|
// return. Therefore the Close must be called from a different goroutine.
|
|
|
|
func WithEventHandler(e EventHandler) EventHandler {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineEdge) applyLineConfig(lc *LineConfig) {
|
|
|
|
lc.EdgeDetection = o
|
|
|
|
lc.Direction = LineDirectionInput
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineEdge) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
o.applyLineConfig(&lro.defCfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineEdge) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
o.applyLineConfig(&lco.defCfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineEdge) applySubsetLineConfigOption(offsets []int, lco *lineConfigOptions) {
|
|
|
|
for _, offset := range offsets {
|
|
|
|
o.applyLineConfig(lco.lineConfig(offset))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithFallingEdge indicates that a line will generate events when its active
|
|
|
|
// state transitions from high to low.
|
|
|
|
//
|
|
|
|
// Events are forwarded to the provided handler function.
|
|
|
|
//
|
|
|
|
// This option sets the Input option and overrides and clears any previous
|
|
|
|
// Output, OpenDrain, or OpenSource options.
|
|
|
|
const WithFallingEdge = LineEdgeFalling
|
|
|
|
|
|
|
|
// WithRisingEdge indicates that a line will generate events when its active
|
|
|
|
// state transitions from low to high.
|
|
|
|
//
|
|
|
|
// Events are forwarded to the provided handler function.
|
|
|
|
//
|
|
|
|
// This option sets the Input option and overrides and clears any previous
|
|
|
|
// Output, OpenDrain, or OpenSource options.
|
|
|
|
const WithRisingEdge = LineEdgeRising
|
|
|
|
|
|
|
|
// WithBothEdges indicates that a line will generate events when its active
|
|
|
|
// state transitions from low to high and from high to low.
|
|
|
|
//
|
|
|
|
// Events are forwarded to the provided handler function.
|
|
|
|
//
|
|
|
|
// This option sets the Input option and overrides and clears any previous
|
|
|
|
// Output, OpenDrain, or OpenSource options.
|
|
|
|
const WithBothEdges = LineEdgeBoth
|
|
|
|
|
|
|
|
// WithoutEdges indicates that a line will not generate events due to active
|
|
|
|
// state transitions.
|
|
|
|
//
|
|
|
|
// This is the default for line requests, but allows the removal of edge
|
|
|
|
// detection by reconfigure.
|
|
|
|
//
|
|
|
|
// This option sets the Input option and overrides and clears any previous
|
|
|
|
// Output, OpenDrain, or OpenSource options.
|
|
|
|
//
|
|
|
|
// The WithoutEdges option requires Linux v5.10 or later.
|
|
|
|
const WithoutEdges = LineEdgeNone
|
|
|
|
|
|
|
|
func (o LineEventClock) applyChipOption(c *ChipOptions) {
|
|
|
|
c.config.EventClock = LineEventClock(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineEventClock) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
lro.defCfg.EventClock = LineEventClock(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineEventClock) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
lco.defCfg.EventClock = LineEventClock(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LineEventClock) applySubsetLineConfigOption(offsets []int, lco *lineConfigOptions) {
|
|
|
|
for _, offset := range offsets {
|
|
|
|
lco.lineConfig(offset).EventClock = LineEventClock(o)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithMonotonicEventClock specifies that the edge event timestamps are sourced
|
|
|
|
// from CLOCK_MONOTONIC.
|
|
|
|
//
|
|
|
|
// This option corresponds to the default event clock configuration and its only
|
|
|
|
// useful application is to clear any previous event clock option in a chain of
|
|
|
|
// LineOptions, before that configuration is applied.
|
|
|
|
const WithMonotonicEventClock = LineEventClockMonotonic
|
|
|
|
|
|
|
|
// WithRealtimeEventClock specifies that the edge event timestamps are sourced
|
|
|
|
// from CLOCK_REALTIME.
|
|
|
|
//
|
|
|
|
// Requires Linux v5.11 or later.
|
|
|
|
const WithRealtimeEventClock = LineEventClockRealtime
|
|
|
|
|
|
|
|
// DebounceOption indicates that a line will be debounced.
|
|
|
|
//
|
|
|
|
// The DebounceOption requires Linux v5.10 or later.
|
|
|
|
type DebounceOption time.Duration
|
|
|
|
|
|
|
|
func (o DebounceOption) applyLineConfig(lc *LineConfig) {
|
|
|
|
lc.Direction = LineDirectionInput
|
|
|
|
lc.Debounced = true
|
|
|
|
lc.DebouncePeriod = time.Duration(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o DebounceOption) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
o.applyLineConfig(&lro.defCfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o DebounceOption) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
o.applyLineConfig(&lco.defCfg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o DebounceOption) applySubsetLineConfigOption(offsets []int, lco *lineConfigOptions) {
|
|
|
|
for _, offset := range offsets {
|
|
|
|
o.applyLineConfig(lco.lineConfig(offset))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithDebounce indicates that a line will be debounced with the specified
|
|
|
|
// debounce period.
|
|
|
|
//
|
|
|
|
// This option sets the Input option and overrides and clears any previous
|
|
|
|
// Output, OpenDrain, or OpenSource options.
|
|
|
|
//
|
|
|
|
// Requires Linux v5.10 or later.
|
|
|
|
func WithDebounce(period time.Duration) DebounceOption {
|
|
|
|
return DebounceOption(period)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ABIVersionOption selects the version of the GPIO ioctl commands to use.
|
|
|
|
//
|
|
|
|
// The default is to use the latest version supported by the kernel.
|
|
|
|
type ABIVersionOption int
|
|
|
|
|
|
|
|
func (o ABIVersionOption) applyChipOption(c *ChipOptions) {
|
|
|
|
c.abi = int(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o ABIVersionOption) applyLineReqOption(l *lineReqOptions) {
|
|
|
|
l.abi = int(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithABIVersion indicates the version of the GPIO ioctls to use.
|
|
|
|
//
|
|
|
|
// The default is to use the latest version supported by the kernel.
|
|
|
|
//
|
|
|
|
// ABI version 2 requires Linux v5.10 or later.
|
|
|
|
func WithABIVersion(version int) ABIVersionOption {
|
|
|
|
return ABIVersionOption(version)
|
|
|
|
}
|
|
|
|
|
|
|
|
// LinesOption specifies line options that are to be applied to a subset of
|
|
|
|
// the lines in a request.
|
|
|
|
type LinesOption struct {
|
|
|
|
offsets []int
|
|
|
|
options []SubsetLineConfigOption
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LinesOption) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
o.applyLineConfigOption(&lro.lineConfigOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o LinesOption) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
for _, option := range o.options {
|
|
|
|
option.applySubsetLineConfigOption(o.offsets, lco)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithLines specifies line options to be applied to a subset of the lines in a
|
|
|
|
// request.
|
|
|
|
//
|
|
|
|
// The offsets should be a strict subset of the offsets provided to
|
|
|
|
// RequestLines().
|
|
|
|
// Any offsets outside that set are ignored.
|
|
|
|
func WithLines(offsets []int, options ...SubsetLineConfigOption) LinesOption {
|
|
|
|
return LinesOption{offsets, options}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DefaultedOption resets the configuration to default values.
|
|
|
|
type DefaultedOption int
|
|
|
|
|
|
|
|
func (o DefaultedOption) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
o.applyLineConfigOption(&lro.lineConfigOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o DefaultedOption) applyLineConfigOption(lco *lineConfigOptions) {
|
|
|
|
lco.defCfg = LineConfig{}
|
|
|
|
lco.values = map[int]int{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o DefaultedOption) applySubsetLineConfigOption(offsets []int, lco *lineConfigOptions) {
|
|
|
|
if len(offsets) == 0 {
|
|
|
|
lco.lineCfg = nil
|
|
|
|
}
|
|
|
|
for _, offset := range offsets {
|
|
|
|
delete(lco.values, offset)
|
|
|
|
delete(lco.lineCfg, offset)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Defaulted resets all configuration options to default values.
|
|
|
|
//
|
|
|
|
// This option provides the means to simply reset all configuration options to
|
|
|
|
// their default values. This is rarely necessary but is made available for
|
|
|
|
// completeness.
|
|
|
|
//
|
|
|
|
// When applied within WithLines() it resets the configuration of the lines to
|
|
|
|
// the default for the request, effectively clearing all previous WithLines()
|
|
|
|
// options for the specified offsets. If no offsets are specified then the
|
|
|
|
// configurarion for all offsets is reset to the request default.
|
|
|
|
//
|
|
|
|
// When applied outside WithLines() it resets the default configuration for the
|
|
|
|
// request itself to default values but leaves any configuration set within
|
|
|
|
// WithLines() unchanged.
|
|
|
|
const Defaulted = DefaultedOption(0)
|
|
|
|
|
|
|
|
// EventBufferSizeOption provides a suggested minimum number of events the
|
|
|
|
// kernel will buffer for the line request.
|
|
|
|
//
|
|
|
|
// The EventBufferSizeOption requires Linux v5.10 or later.
|
|
|
|
type EventBufferSizeOption int
|
|
|
|
|
|
|
|
func (o EventBufferSizeOption) applyLineReqOption(lro *lineReqOptions) {
|
|
|
|
lro.eventBufferSize = int(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithEventBufferSize suggests a minimum number of events the kernel will
|
|
|
|
// buffer for the line request.
|
|
|
|
//
|
|
|
|
// Note that the value is only a suggestion, and the kernel may set higher
|
|
|
|
// values or place a cap on the buffer size.
|
|
|
|
//
|
|
|
|
// A zero value (the default) indicates that the kernel should use its default
|
|
|
|
// buffer size (the number of requested lines * 16).
|
|
|
|
//
|
|
|
|
// Requires Linux v5.10 or later.
|
|
|
|
func WithEventBufferSize(size int) EventBufferSizeOption {
|
|
|
|
return EventBufferSizeOption(size)
|
|
|
|
}
|