2022-11-27 23:06:09 +08:00
|
|
|
package system
|
|
|
|
|
|
|
|
import (
|
2023-01-28 19:22:32 +08:00
|
|
|
"time"
|
|
|
|
|
2023-05-20 20:25:21 +08:00
|
|
|
"gobot.io/x/gobot/v2"
|
2022-11-27 23:06:09 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// IN gpio direction
|
|
|
|
IN = "in"
|
|
|
|
// OUT gpio direction
|
|
|
|
OUT = "out"
|
|
|
|
// HIGH gpio level
|
|
|
|
HIGH = 1
|
|
|
|
// LOW gpio level
|
|
|
|
LOW = 0
|
|
|
|
)
|
|
|
|
|
2023-01-28 19:22:32 +08:00
|
|
|
const (
|
|
|
|
digitalPinBiasDefault = 0 // GPIO uses the hardware default
|
|
|
|
digitalPinBiasDisable = 1 // GPIO has pull disabled
|
|
|
|
digitalPinBiasPullDown = 2 // GPIO has pull up enabled
|
|
|
|
digitalPinBiasPullUp = 3 // GPIO has pull down enabled
|
|
|
|
|
|
|
|
// open drain and open source allows the connection of output ports with the same mode (OR logic)
|
|
|
|
// * for open drain/collector pull up the ports with an external resistor/load
|
|
|
|
// * for open source/emitter pull down the ports with an external resistor/load
|
|
|
|
digitalPinDrivePushPull = 0 // the pin will be driven actively high and low (default)
|
|
|
|
digitalPinDriveOpenDrain = 1 // the pin will be driven active to low only
|
|
|
|
digitalPinDriveOpenSource = 2 // the pin will be driven active to high only
|
|
|
|
|
|
|
|
digitalPinEventNone = 0 // no event will be triggered on any pin change (default)
|
|
|
|
digitalPinEventOnFallingEdge = 1 // an event will be triggered on changes from high to low state
|
|
|
|
digitalPinEventOnRisingEdge = 2 // an event will be triggered on changes from low to high state
|
|
|
|
digitalPinEventOnBothEdges = 3 // an event will be triggered on all changes
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// DigitalPinEventRisingEdge indicates an inactive to active event.
|
|
|
|
DigitalPinEventRisingEdge = "rising edge"
|
|
|
|
// DigitalPinEventFallingEdge indicates an active to inactive event.
|
|
|
|
DigitalPinEventFallingEdge = "falling edge"
|
|
|
|
)
|
|
|
|
|
2022-11-27 23:06:09 +08:00
|
|
|
type digitalPinConfig struct {
|
2023-01-28 19:22:32 +08:00
|
|
|
label string
|
|
|
|
direction string
|
|
|
|
outInitialState int
|
|
|
|
activeLow bool
|
|
|
|
bias int
|
|
|
|
drive int
|
|
|
|
debouncePeriod time.Duration
|
|
|
|
edge int
|
|
|
|
edgeEventHandler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32, lseqno uint32)
|
2022-11-27 23:06:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func newDigitalPinConfig(label string, options ...func(gobot.DigitalPinOptioner) bool) *digitalPinConfig {
|
|
|
|
cfg := &digitalPinConfig{
|
|
|
|
label: label,
|
|
|
|
direction: IN,
|
|
|
|
}
|
|
|
|
for _, option := range options {
|
|
|
|
option(cfg)
|
|
|
|
}
|
|
|
|
return cfg
|
|
|
|
}
|
|
|
|
|
2023-01-28 19:22:32 +08:00
|
|
|
// WithPinLabel use a pin label, which will replace the default label "gobotio#".
|
|
|
|
func WithPinLabel(label string) func(gobot.DigitalPinOptioner) bool {
|
2022-11-27 23:06:09 +08:00
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetLabel(label) }
|
|
|
|
}
|
|
|
|
|
2023-01-28 19:22:32 +08:00
|
|
|
// WithPinDirectionOutput initializes the pin as output instead of the default "input".
|
|
|
|
func WithPinDirectionOutput(initial int) func(gobot.DigitalPinOptioner) bool {
|
2022-11-27 23:06:09 +08:00
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetDirectionOutput(initial) }
|
|
|
|
}
|
|
|
|
|
2023-01-28 19:22:32 +08:00
|
|
|
// WithPinDirectionInput initializes the pin as input.
|
|
|
|
func WithPinDirectionInput() func(gobot.DigitalPinOptioner) bool {
|
2022-11-27 23:06:09 +08:00
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetDirectionInput() }
|
|
|
|
}
|
|
|
|
|
2023-01-28 19:22:32 +08:00
|
|
|
// WithPinActiveLow initializes the pin with inverse reaction (applies on input and output).
|
|
|
|
func WithPinActiveLow() func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetActiveLow() }
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPinPullDown initializes the pin to be pulled down (high impedance to GND, applies on input and output).
|
|
|
|
// This is working since Kernel 5.5.
|
|
|
|
func WithPinPullDown() func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetBias(digitalPinBiasPullDown) }
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPinPullUp initializes the pin to be pulled up (high impedance to VDD, applies on input and output).
|
|
|
|
// This is working since Kernel 5.5.
|
|
|
|
func WithPinPullUp() func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetBias(digitalPinBiasPullUp) }
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPinOpenDrain initializes the output pin to be driven with open drain/collector.
|
|
|
|
func WithPinOpenDrain() func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetDrive(digitalPinDriveOpenDrain) }
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPinOpenSource initializes the output pin to be driven with open source/emitter.
|
|
|
|
func WithPinOpenSource() func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetDrive(digitalPinDriveOpenSource) }
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPinDebounce initializes the input pin to be debounced.
|
|
|
|
func WithPinDebounce(period time.Duration) func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool { return d.SetDebounce(period) }
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPinEventOnFallingEdge initializes the input pin for edge detection and call the event handler on falling edges.
|
|
|
|
func WithPinEventOnFallingEdge(handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32,
|
|
|
|
lseqno uint32)) func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool {
|
|
|
|
return d.SetEventHandlerForEdge(handler, digitalPinEventOnFallingEdge)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPinEventOnRisingEdge initializes the input pin for edge detection and call the event handler on rising edges.
|
|
|
|
func WithPinEventOnRisingEdge(handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32,
|
|
|
|
lseqno uint32)) func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool {
|
|
|
|
return d.SetEventHandlerForEdge(handler, digitalPinEventOnRisingEdge)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPinEventOnBothEdges initializes the input pin for edge detection and call the event handler on all edges.
|
|
|
|
func WithPinEventOnBothEdges(handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32,
|
|
|
|
lseqno uint32)) func(gobot.DigitalPinOptioner) bool {
|
|
|
|
return func(d gobot.DigitalPinOptioner) bool {
|
|
|
|
return d.SetEventHandlerForEdge(handler, digitalPinEventOnBothEdges)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLabel sets the label to use for next reconfigure. The function is intended to use by WithPinLabel().
|
2022-11-27 23:06:09 +08:00
|
|
|
func (d *digitalPinConfig) SetLabel(label string) bool {
|
|
|
|
if d.label == label {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d.label = label
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-01-28 19:22:32 +08:00
|
|
|
// SetDirectionOutput sets the direction to output for next reconfigure. The function is intended to use
|
|
|
|
// by WithPinDirectionOutput().
|
2022-11-27 23:06:09 +08:00
|
|
|
func (d *digitalPinConfig) SetDirectionOutput(initial int) bool {
|
|
|
|
if d.direction == OUT {
|
|
|
|
// in this case also the initial value will not be written
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d.direction = OUT
|
|
|
|
d.outInitialState = initial
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-01-28 19:22:32 +08:00
|
|
|
// SetDirectionInput sets the direction to input for next reconfigure. The function is intended to use
|
|
|
|
// by WithPinDirectionInput().
|
2022-11-27 23:06:09 +08:00
|
|
|
func (d *digitalPinConfig) SetDirectionInput() bool {
|
|
|
|
if d.direction == IN {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d.direction = IN
|
|
|
|
return true
|
|
|
|
}
|
2023-01-28 19:22:32 +08:00
|
|
|
|
|
|
|
// SetActiveLow sets the pin with inverse reaction (applies on input and output) for next reconfigure. The function
|
|
|
|
// is intended to use by WithPinActiveLow().
|
|
|
|
func (d *digitalPinConfig) SetActiveLow() bool {
|
|
|
|
if d.activeLow {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d.activeLow = true
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetBias sets the pin bias (applies on input and output) for next reconfigure. The function
|
|
|
|
// is intended to use by WithPinPullUp() and WithPinPullDown().
|
|
|
|
func (d *digitalPinConfig) SetBias(bias int) bool {
|
|
|
|
if d.bias == bias {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d.bias = bias
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetDrive sets the pin drive mode (applies on output only) for next reconfigure. The function
|
|
|
|
// is intended to use by WithPinOpenDrain(), WithPinOpenSource() and WithPinPushPull().
|
|
|
|
func (d *digitalPinConfig) SetDrive(drive int) bool {
|
|
|
|
if d.drive == drive {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d.drive = drive
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetDebounce sets the input pin with the given debounce period for next reconfigure. The function
|
|
|
|
// is intended to use by WithPinDebounce().
|
|
|
|
func (d *digitalPinConfig) SetDebounce(period time.Duration) bool {
|
|
|
|
if d.debouncePeriod == period {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d.debouncePeriod = period
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetEventHandlerForEdge sets the input pin to edge detection and to call the event handler on specified edge. The
|
|
|
|
// function is intended to use by WithPinEventOnFallingEdge(), WithPinEventOnRisingEdge() and WithPinEventOnBothEdges().
|
|
|
|
func (d *digitalPinConfig) SetEventHandlerForEdge(handler func(int, time.Duration, string, uint32, uint32), edge int) bool {
|
|
|
|
if d.edge == edge {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
d.edge = edge
|
|
|
|
d.edgeEventHandler = handler
|
|
|
|
return true
|
|
|
|
}
|