A quick and dirty implementation
This commit is contained in:
parent
3682810e27
commit
f6e9c70eb3
352 changed files with 242881 additions and 0 deletions
1
vendor/github.com/warthog618/gpiod/.gitignore
generated
vendored
Normal file
1
vendor/github.com/warthog618/gpiod/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.test
|
21
vendor/github.com/warthog618/gpiod/.travis.yml
generated
vendored
Normal file
21
vendor/github.com/warthog618/gpiod/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- "1.x"
|
||||
- "1.13"
|
||||
- tip
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
fast_finish: true
|
||||
|
||||
install:
|
||||
- go get -v ./...
|
||||
|
||||
script:
|
||||
- go vet ./...
|
||||
- make
|
21
vendor/github.com/warthog618/gpiod/LICENSE
generated
vendored
Normal file
21
vendor/github.com/warthog618/gpiod/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Kent Gibson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
28
vendor/github.com/warthog618/gpiod/Makefile
generated
vendored
Normal file
28
vendor/github.com/warthog618/gpiod/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
GOCMD=go
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOCLEAN=$(GOCMD) clean
|
||||
|
||||
VERSION ?= $(shell git describe --tags --always --dirty 2> /dev/null )
|
||||
LDFLAGS=-ldflags "-X=main.version=$(VERSION)"
|
||||
|
||||
spis=$(patsubst %.go, %, $(wildcard example/spi/*/*.go))
|
||||
examples=$(patsubst %.go, %, $(wildcard example/*/*.go))
|
||||
bins= $(spis) $(examples)
|
||||
|
||||
cmds=$(patsubst %.go, %, $(wildcard cmd/gpio*/gpio*.go))
|
||||
|
||||
all: tools $(bins)
|
||||
|
||||
$(cmds) : % : %.go
|
||||
cd $(@D); \
|
||||
$(GOBUILD) $(LDFLAGS)
|
||||
|
||||
$(bins) : % : %.go
|
||||
cd $(@D); \
|
||||
$(GOBUILD)
|
||||
|
||||
clean:
|
||||
$(GOCLEAN) ./...
|
||||
|
||||
tools: $(cmds)
|
||||
|
439
vendor/github.com/warthog618/gpiod/README.md
generated
vendored
Normal file
439
vendor/github.com/warthog618/gpiod/README.md
generated
vendored
Normal file
|
@ -0,0 +1,439 @@
|
|||
# gpiod
|
||||
|
||||
[](https://travis-ci.org/warthog618/gpiod)
|
||||
[](https://pkg.go.dev/github.com/warthog618/gpiod)
|
||||
[](https://goreportcard.com/report/github.com/warthog618/gpiod)
|
||||
[](https://github.com/warthog618/gpiod/blob/master/LICENSE)
|
||||
|
||||
A native Go library for Linux GPIO.
|
||||
|
||||
**gpiod** is a library for accessing GPIO pins/lines on Linux platforms using
|
||||
the GPIO character device.
|
||||
|
||||
The goal of this library is to provide the Go equivalent of the C
|
||||
**[libgpiod](https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/)**
|
||||
library. The intent is not to mirror the **libgpiod** API but to provide the
|
||||
equivalent functionality.
|
||||
|
||||
## Features
|
||||
|
||||
Supports the following functionality per line and for collections of lines:
|
||||
|
||||
- direction (input/output)<sup>1</sup>
|
||||
- write (active/inactive)
|
||||
- read (active/inactive)
|
||||
- active high/low (defaults to high)
|
||||
- output mode (normal/open-drain/open-source)
|
||||
- pull up/down<sup>2</sup>
|
||||
- watches and edge detection (rising/falling/both)
|
||||
- chip and line labels
|
||||
|
||||
<sup>1</sup>Dynamically changing line direction without releasing the line
|
||||
requires Linux v5.5 or later.
|
||||
|
||||
<sup>2</sup>Pull up/down support requires Linux v5.5 or later.
|
||||
|
||||
All library functions are safe to call from different goroutines.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import "github.com/warthog618/gpiod"
|
||||
```
|
||||
|
||||
Error handling is omitted from the following examples for brevity.
|
||||
|
||||
### Chip Initialization
|
||||
|
||||
The Chip object is used to request lines from a GPIO chip.
|
||||
|
||||
A Chip object is constructed using the
|
||||
[*NewChip*](https://pkg.go.dev/github.com/warthog618/gpiod#NewChip) function.
|
||||
|
||||
```go
|
||||
c, _ := gpiod.NewChip("gpiochip0")
|
||||
```
|
||||
|
||||
The parameter is the chip name, which corresponds to the name of the device in
|
||||
the **/dev** directory, so in this example **/dev/gpiochip0**.
|
||||
|
||||
Default attributes for Lines requested from the Chip can be set via
|
||||
[options](#line-options) to
|
||||
[*NewChip*](https://pkg.go.dev/github.com/warthog618/gpiod#NewChip).
|
||||
|
||||
```go
|
||||
c, _ := gpiod.NewChip("gpiochip0", gpiod.WithConsumer("myapp"))
|
||||
```
|
||||
|
||||
In this example the consumer label is defaulted to "myapp".
|
||||
|
||||
When no longer required, the chip should be closed to release resources:
|
||||
|
||||
```go
|
||||
c.Close()
|
||||
```
|
||||
|
||||
Closing a chip does not close or otherwise alter the state of any lines
|
||||
requested from the chip.
|
||||
|
||||
### Line Requests
|
||||
|
||||
To alter the state of a
|
||||
[line](https://pkg.go.dev/github.com/warthog618/gpiod#Line) it must first be
|
||||
requested from the Chip, using
|
||||
[*Chip.RequestLine*](https://pkg.go.dev/github.com/warthog618/gpiod#Chip.RequestLine):
|
||||
|
||||
```go
|
||||
l, _ := c.RequestLine(4) // in its existing state
|
||||
```
|
||||
|
||||
The offset parameter identifies the line on the chip, and is specific to the
|
||||
GPIO chip. To improve readability, convenience mappings can be provided for
|
||||
specific devices, such as the Raspberry Pi:
|
||||
|
||||
```go
|
||||
l, _ := c.RequestLine(rpi.J8p7) // using Raspberry Pi J8 mapping
|
||||
```
|
||||
|
||||
The initial state of the line can be set by providing [line
|
||||
options](#line-options), as shown in this *AsOutput* example:
|
||||
|
||||
```go
|
||||
l, _ := c.RequestLine(4,gpiod.AsOutput(1)) // as an output line
|
||||
```
|
||||
|
||||
Multiple lines from the same chip may be requested as a collection of
|
||||
[lines](https://pkg.go.dev/github.com/warthog618/gpiod#Lines) using
|
||||
[*Chip.RequestLines*](https://pkg.go.dev/github.com/warthog618/gpiod#Chip.RequestLines):
|
||||
|
||||
```go
|
||||
ll, _ := c.RequestLines([]int{0, 1, 2, 3}, gpiod.AsOutput(0, 0, 1, 1))
|
||||
```
|
||||
|
||||
Note that [line options](#line-options) applied to a collection of lines apply
|
||||
to all lines in the collection.
|
||||
|
||||
When no longer required, the line(s) should be closed to release resources:
|
||||
|
||||
```go
|
||||
l.Close()
|
||||
ll.Close()
|
||||
```
|
||||
|
||||
### Line Info
|
||||
|
||||
[Info](https://pkg.go.dev/github.com/warthog618/gpiod#LineInfo) about a line can
|
||||
be read at any time from the chip using the
|
||||
[*LineInfo*](https://pkg.go.dev/github.com/warthog618/gpiod#Chip.LineInfo)
|
||||
method:
|
||||
|
||||
```go
|
||||
inf, _ := c.LineInfo(4)
|
||||
inf, _ := c.LineInfo(rpi.J8p7) // Using Raspberry Pi J8 mapping
|
||||
```
|
||||
|
||||
Note that the line info does not include the value. The line must be requested
|
||||
from the chip to access the value. Once requested, the line info can also be
|
||||
read from the line:
|
||||
|
||||
```go
|
||||
inf, _ := l.Info()
|
||||
infs, _ := ll.Info()
|
||||
```
|
||||
|
||||
### Direction
|
||||
|
||||
The line direction can be controlled using the *AsInput* and *AsOutput* [line
|
||||
options](#line-options):
|
||||
|
||||
```go
|
||||
l, _ := c.RequestLine(4,gpiod.AsInput) // during request
|
||||
l.Reconfigure(gpiod.AsInput) // set direction to Input
|
||||
l.Reconfigure(gpiod.AsOutput(0)) // set direction to Output (and value to inactive)
|
||||
```
|
||||
|
||||
### Read Input
|
||||
|
||||
The current line level can be read with the
|
||||
[*Value*](https://pkg.go.dev/github.com/warthog618/gpiod#Line.Value)
|
||||
method:
|
||||
|
||||
```go
|
||||
r, _ := l.Value() // Read state from line (active / inactive)
|
||||
```
|
||||
|
||||
For collections of lines, the level of all lines is read simultaneously using
|
||||
the [*Values*](https://pkg.go.dev/github.com/warthog618/gpiod#Lines.SetValues)
|
||||
method:
|
||||
|
||||
```go
|
||||
rr := []int{0, 0, 0, 0} // buffer to read into...
|
||||
ll.Values(rr) // Read the state of a collection of lines
|
||||
```
|
||||
|
||||
### Write Output
|
||||
|
||||
The current line level can be set with the
|
||||
[*SetValue*](https://pkg.go.dev/github.com/warthog618/gpiod#Line.SetValue)
|
||||
method:
|
||||
|
||||
```go
|
||||
l.SetValue(1) // Set line active
|
||||
l.SetValue(0) // Set line inactive
|
||||
```
|
||||
|
||||
Also refer to the [blinker](example/blinker/blinker.go) example.
|
||||
|
||||
For collections of lines, all lines are set simultaneously using the
|
||||
[*SetValues*](https://pkg.go.dev/github.com/warthog618/gpiod#Lines.SetValues)
|
||||
method:
|
||||
|
||||
```go
|
||||
ll.SetValues([]int{0, 1, 0, 1}) // Set a collection of lines
|
||||
```
|
||||
|
||||
### Watches
|
||||
|
||||
The state of an input line can be watched and trigger calls to handler
|
||||
functions.
|
||||
|
||||
The watch can be on rising or falling edges, or both.
|
||||
|
||||
The handler function is passed a
|
||||
[*LineEvent*](https://pkg.go.dev/github.com/warthog618/gpiod#LineEvent), which
|
||||
contains the offset of the triggering line, the time the edge was detected and
|
||||
the type of edge detected:
|
||||
|
||||
```go
|
||||
func handler(evt gpiod.LineEvent) {
|
||||
// handle change in line state
|
||||
}
|
||||
|
||||
l, _ := c.RequestLine(rpi.J8p7, gpiod.WithBothEdges(handler)))
|
||||
```
|
||||
|
||||
A watch can be removed by closing the line:
|
||||
|
||||
```go
|
||||
l.Close()
|
||||
```
|
||||
|
||||
Also see the [watcher](example/watcher/watcher.go) example.
|
||||
|
||||
### Find
|
||||
|
||||
Lines can be found by the GPIO label name as returned in line info and set by
|
||||
device-tree using the
|
||||
[*FindLine*](https://pkg.go.dev/github.com/warthog618/gpiod#FindLine) function:
|
||||
|
||||
```go
|
||||
chipname, offset, _ := gpiod.FindLine("LED A")
|
||||
c, _ := gpiod.NewChip(chipname, gpiod.WithConsumer("myapp"))
|
||||
l, _ := c.RequestLine(offset)
|
||||
```
|
||||
|
||||
### Active Level
|
||||
|
||||
The values used throughout the API for line values are the logical value, which
|
||||
is 0 for inactive and 1 for active. The physical level considered active can be
|
||||
controlled using the *AsActiveHigh* and *AsActiveLow* [line
|
||||
options](#line-options):
|
||||
|
||||
```go
|
||||
l, _ := c.RequestLine(4,gpiod.AsActiveLow) // during request
|
||||
l.Reconfigure(gpiod.AsActiveHigh) // once requested
|
||||
```
|
||||
|
||||
Lines are typically active high by default.
|
||||
|
||||
### Bias
|
||||
|
||||
The bias [line options](#line-options) control the pull up/down state of the
|
||||
line:
|
||||
|
||||
```go
|
||||
l,_ := c.RequestLine(4,gpiod.WithPullUp) // during request
|
||||
l.Reconfigure(gpiod.WithBiasDisable) // once requested
|
||||
```
|
||||
|
||||
Note that bias options require Linux v5.5 or later.
|
||||
|
||||
### Drive
|
||||
|
||||
The drive options control how an output line is driven when active and inactive:
|
||||
|
||||
```go
|
||||
l,_ := c.RequestLine(4,gpiod.AsOpenDrain) // during request
|
||||
l.Reconfigure(gpiod.AsOpenSource) // once requested
|
||||
```
|
||||
|
||||
The default drive for output lines is push-pull, which drives the line in both
|
||||
directions.
|
||||
|
||||
### Line Options
|
||||
|
||||
Line attributes are set via options to *Chip.RequestLine(s)* and
|
||||
*Line.Reconfigure*. These override any default which may be set in *NewChip*.
|
||||
Only one option from each category may be applied. If multiple options from a
|
||||
category are applied then all but the last are ignored.
|
||||
|
||||
The line options are:
|
||||
|
||||
Option | Category | Description
|
||||
---|---|---
|
||||
*WithConsumer*<sup>1</sup>|Info|Set the consumer label for the lines
|
||||
*AsActiveLow*|Level|Treat a low physical line level as active
|
||||
*AsActiveHigh*|Level|Treat a high physical line level as active (default)
|
||||
*AsInput*|Direction|Request lines as input
|
||||
*AsIs*<sup>2</sup>|Direction|Request lines in their current input/output state (default)
|
||||
*AsOutput(\<values\>...)*<sup>3</sup>|Direction|Request lines as output with initial values
|
||||
*AsPushPull*|Drive<sup>3</sup>|Request output lines drive both high and low (default)
|
||||
*AsOpenDrain*|Drive<sup>3</sup>|Request lines as open drain outputs
|
||||
*AsOpenSource*|Drive<sup>3</sup>|Request lines as open source outputs
|
||||
*WithFallingEdge(eh)*|Edge<sup>4</sup>|Request lines with falling edge detection, with events passed to the provided event handler
|
||||
*WithRisingEdge(eh)*|Edge<sup>4</sup>|Request lines with rising edge detection, with events passed to the provided event handler
|
||||
*WithBothEdges(eh)*|Edge<sup>4</sup>|Request lines with rising and falling edge detection, with events passed to the provided event handler
|
||||
*WithBiasDisable*|Bias<sup>5</sup>|Request the lines have internal bias disabled
|
||||
*WithPullDown*|Bias<sup>5</sup>|Request the lines have internal pull-down enabled
|
||||
*WithPullUp*|Bias<sup>5</sup>|Request the lines have internal pull-up enabled
|
||||
|
||||
<sup>1</sup> WithConsumer can be provided to either *NewChip* or
|
||||
*Chip.RequestLine(s)*, and cannot be used with *Line.Reconfigure*.
|
||||
|
||||
<sup>2</sup> The AsIs option can only be provided to *Chip.RequestLine(s)*, and
|
||||
cannot be used with *NewChip* or *Line.Reconfigure*.
|
||||
|
||||
<sup>3</sup> The AsOutput and Drive options can only be provided to either
|
||||
*Chip.RequestLine(s)* or *Line.Reconfigure*, and cannot be used with *NewChip*.
|
||||
|
||||
<sup>4</sup> Edge options can only be provided to *Chip.RequestLine(s)*, and
|
||||
cannot be used with *NewChip* or *Line.Reconfigure*.
|
||||
|
||||
<sup>5</sup> Bias options require Linux v5.5 or later.
|
||||
|
||||
## Tools
|
||||
|
||||
A command line utility, **gpiodctl**, can be found in the cmd directory and is
|
||||
provided to allow manual or scripted manipulation of GPIO lines. This utility
|
||||
combines the Go equivalent of all the **libgpiod** command line tools into a
|
||||
single tool.
|
||||
|
||||
```sh
|
||||
gpiodctl is a utility to control GPIO lines on Linux GPIO character devices
|
||||
|
||||
Usage:
|
||||
gpiodctl [flags]
|
||||
gpiodctl [command]
|
||||
|
||||
Available Commands:
|
||||
detect Detect available GPIO chips
|
||||
find Find a GPIO line by name
|
||||
get Get the state of a line
|
||||
help Help about any command
|
||||
info Info about chip lines
|
||||
mon Monitor the state of a line
|
||||
set Set the state of a line
|
||||
version Display the version
|
||||
|
||||
Flags:
|
||||
-h, --help help for gpiodctl
|
||||
|
||||
Use "gpiodctl [command] --help" for more information about a command.
|
||||
|
||||
```
|
||||
|
||||
The Go equivalent of each of the **libgpiod** command line tools can also be
|
||||
found in the cmd directory.
|
||||
|
||||
Those tools are:
|
||||
|
||||
Tool | Description
|
||||
--- | ---
|
||||
gpiodetect | Report all the gpiochips available on the system.
|
||||
gpioinfo | Report the details of all the lines available on gpiochips.
|
||||
gpiofind | Find the gpiochip and offset of a line by name.
|
||||
gpioget | Get the value of a line or a set of lines on one gpiochip.
|
||||
gpioset | Set of value of a line or a set of lines on one gpiochip.
|
||||
gpiomon | Report edges detected on a line or set of lines on one gpiochip.
|
||||
|
||||
## Tests
|
||||
|
||||
The library is fully tested, other than some error cases and sanity checks that
|
||||
are difficult to trigger.
|
||||
|
||||
The tests require a kernel release 5.1.0 or later to run. For all the tests to
|
||||
pass a kernel 5.5.0 or later is required.
|
||||
|
||||
The test user must have access to the **/dev/gpiochip0** character device.
|
||||
|
||||
### Platforms
|
||||
|
||||
The tests can be run on either of two platforms:
|
||||
|
||||
- gpio-mockup (default)
|
||||
- Raspberry Pi
|
||||
|
||||
#### gpio-mockup
|
||||
|
||||
The gpio-mockup platform is any Linux platform with a recent kernel that supports
|
||||
the **gpio-mockup** loadable module. **gpio-mockup** must be built as a module
|
||||
and the test user must have rights to load and unload the module.
|
||||
|
||||
The **gpio-mockup** is the default platform for tests and benchmarks as it does not interact with physical hardware and so is always safe to run.
|
||||
|
||||
#### Raspberry Pi
|
||||
|
||||
On Raspberry Pi, the tests are intended to be run on a board with J8 pins 11 and
|
||||
12 floating and with pins 15 and 16 tied together, possibly using a jumper
|
||||
across the header. The tests set J8 pins 11, 12 and 16 to outputs so **DO NOT**
|
||||
run them on hardware where any of those pins is being externally driven.
|
||||
|
||||
The Raspberry Pi platform is selected by specifying the platform parameter on the test command line:
|
||||
|
||||
```sh
|
||||
go test -platform=rpi
|
||||
```
|
||||
|
||||
Tests have been run successfully on Raspberry Pi Zero W and Pi 4B. The library
|
||||
should also work on other Raspberry Pi variants, I just haven't gotten around to
|
||||
testing them yet.
|
||||
|
||||
The tests can be cross-compiled from other platforms using:
|
||||
|
||||
```sh
|
||||
GOOS=linux GOARCH=arm GOARM=6 go test -c
|
||||
```
|
||||
|
||||
Later Pis can also use ARM7 (GOARM=7).
|
||||
|
||||
### Benchmarks
|
||||
|
||||
The tests include benchmarks on reads, writes, bulk reads and writes, and
|
||||
interrupt latency.
|
||||
|
||||
These are the results from a Raspberry Pi Zero W built with Go 1.13:
|
||||
|
||||
```sh
|
||||
$ ./gpiod.test -platform=rpi -test.bench=.*
|
||||
goos: linux
|
||||
goarch: arm
|
||||
pkg: gpiod
|
||||
BenchmarkLineValue 157851 7160 ns/op
|
||||
BenchmarkLinesValues 152865 7599 ns/op
|
||||
BenchmarkLineSetValue 171585 6782 ns/op
|
||||
BenchmarkLinesSetValues 155041 7995 ns/op
|
||||
BenchmarkInterruptLatency 2041 581938 ns/op
|
||||
PASS
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The library targets Linux with support for the GPIO character device API. That
|
||||
generally means that **/dev/gpiochip0** exists.
|
||||
|
||||
The Bias line options and the Line.Reconfigure method both require Linux v5.5 or
|
||||
later.
|
||||
|
||||
The caller must have access to the character device - typically
|
||||
**/dev/gpiochip0**. That is generally root unless you have changed the
|
||||
permissions of that device.
|
13
vendor/github.com/warthog618/gpiod/go.mod
generated
vendored
Normal file
13
vendor/github.com/warthog618/gpiod/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
module github.com/warthog618/gpiod
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/pilebones/go-udev v0.0.0-20180820235104-043677e09b13
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/warthog618/config v0.4.1
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
)
|
220
vendor/github.com/warthog618/gpiod/go.sum
generated
vendored
Normal file
220
vendor/github.com/warthog618/gpiod/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,220 @@
|
|||
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.15+incompatible h1:+9RjdC18gMxNQVvSiXvObLu29mOFmkgdsB4cRTlV+EE=
|
||||
github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
|
||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.11.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pilebones/go-udev v0.0.0-20180820235104-043677e09b13 h1:Y+ynP+0QIjUejN2tsuIlWOJG1CThJy6amRuWlBL94Vg=
|
||||
github.com/pilebones/go-udev v0.0.0-20180820235104-043677e09b13/go.mod h1:MXAPLpvZeTqLpU1eO6kFXzU0uBMooSGc1MPXAcBoy1M=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/warthog618/config v0.4.1 h1:yn0t8OUbgaAcGMrVRbROEKE5D3aeNR4khkHxJjBiDXs=
|
||||
github.com/warthog618/config v0.4.1/go.mod h1:IzcIkVay6dCubN3WBAJzPuqHyE1fTPxICvKTQ/2JA9g=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.2.0 h1:6I+W7f5VwC5SV9dNrZ3qXrDB9mD0dyGOi/ZJmYw03T4=
|
||||
go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190927073244-c990c680b611 h1:q9u40nxWT5zRClI/uU9dHCiYGottAg6Nzz4YUQyHxdA=
|
||||
golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c h1:hrpEMCZ2O7DR5gC1n2AJGVhrwiEjOi35+jxtIuZpTMo=
|
||||
google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.48.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
830
vendor/github.com/warthog618/gpiod/gpiod.go
generated
vendored
Normal file
830
vendor/github.com/warthog618/gpiod/gpiod.go
generated
vendored
Normal file
|
@ -0,0 +1,830 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2019 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
// Package gpiod is a library for accessing GPIO pins/lines on Linux platforms
|
||||
// using the GPIO character device.
|
||||
//
|
||||
// This is a Go equivalent of libgpiod.
|
||||
//
|
||||
// Supports:
|
||||
// - Line direction (input/output)
|
||||
// - Line write (active/inactive)
|
||||
// - Line read (active/inactive)
|
||||
// - Line bias (pull-up/pull-down/disabled)
|
||||
// - Line drive (push-pull/open-drain/open-source)
|
||||
// - Line level (active-high/active-low)
|
||||
// - Line edge detection (rising/falling/both)
|
||||
// - Line labels
|
||||
// - Collections of lines for near simultaneous reads and writes on multiple lines
|
||||
//
|
||||
// Example of use:
|
||||
//
|
||||
// c, err := gpiod.NewChip("gpiochip0")
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// v := 0
|
||||
// l, err := c.RequestLine(4, gpiod.AsOutput(v))
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// for {
|
||||
// <-time.After(time.Second)
|
||||
// v ^= 1
|
||||
// l.SetValue(v)
|
||||
// }
|
||||
//
|
||||
package gpiod
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/warthog618/gpiod/uapi"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Chip represents a single GPIO chip that controls a set of lines.
|
||||
type Chip struct {
|
||||
f *os.File
|
||||
// The system name for this chip.
|
||||
Name string
|
||||
|
||||
// A more individual label for the chip.
|
||||
Label string
|
||||
|
||||
// The number of GPIO lines on this chip.
|
||||
lines int
|
||||
|
||||
// default options for reserved lines.
|
||||
options ChipOptions
|
||||
|
||||
// mutex covers the attributes below it.
|
||||
mu sync.Mutex
|
||||
|
||||
// watcher for line info changes
|
||||
iw *infoWatcher
|
||||
|
||||
// handlers for info changes in watched lines, keyed by offset.
|
||||
ich map[int]InfoChangeHandler
|
||||
|
||||
// indicates the chip has been closed.
|
||||
closed bool
|
||||
}
|
||||
|
||||
// LineInfo contains a summary of publicly available information about the
|
||||
// line.
|
||||
type LineInfo struct {
|
||||
// The line offset within the chip.
|
||||
Offset int
|
||||
|
||||
// The system name for the line.
|
||||
Name string
|
||||
|
||||
// A string identifying the requester of the line, if requested.
|
||||
Consumer string
|
||||
|
||||
// True if the line is requested.
|
||||
Requested bool
|
||||
|
||||
// True if the line was requested as an output.
|
||||
IsOut bool
|
||||
|
||||
// True if the line was requested as active low.
|
||||
ActiveLow bool
|
||||
|
||||
// True if the line was requested as open drain.
|
||||
//
|
||||
// Only valid for outputs.
|
||||
OpenDrain bool
|
||||
|
||||
// True if the line was requested as open source.
|
||||
//
|
||||
// Only valid for outputs.
|
||||
OpenSource bool
|
||||
|
||||
// True if the line was requested with bias disabled.
|
||||
BiasDisable bool
|
||||
|
||||
// True if the line was requested with pull-down.
|
||||
PullDown bool
|
||||
|
||||
// True if the line was requested with pull-up.
|
||||
PullUp bool
|
||||
}
|
||||
|
||||
// Chips returns the names of the available GPIO devices.
|
||||
func Chips() []string {
|
||||
cc := []string(nil)
|
||||
for _, name := range chipNames() {
|
||||
if IsChip(name) == nil {
|
||||
cc = append(cc, name)
|
||||
}
|
||||
}
|
||||
return cc
|
||||
}
|
||||
|
||||
// FindLine finds the chip and offset of the named line.
|
||||
//
|
||||
// Returns an error if the line cannot be found.
|
||||
func FindLine(lname string) (string, int, error) {
|
||||
c, o, err := findLine(lname)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
c.Close()
|
||||
return c.Name, o, nil
|
||||
}
|
||||
|
||||
// NewChip opens a GPIO character device.
|
||||
func NewChip(name string, options ...ChipOption) (*Chip, error) {
|
||||
path := nameToPath(name)
|
||||
err := IsChip(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
co := ChipOptions{
|
||||
consumer: fmt.Sprintf("gpiod-%d", os.Getpid()),
|
||||
}
|
||||
for _, option := range options {
|
||||
option.applyChipOption(&co)
|
||||
}
|
||||
f, err := os.OpenFile(path, unix.O_CLOEXEC, unix.O_RDONLY)
|
||||
if err != nil {
|
||||
// only happens if device removed/locked since IsChip call.
|
||||
return nil, err
|
||||
}
|
||||
ci, err := uapi.GetChipInfo(f.Fd())
|
||||
if err != nil {
|
||||
// only occurs if IsChip was wrong?
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
c := Chip{
|
||||
f: f,
|
||||
Name: uapi.BytesToString(ci.Name[:]),
|
||||
Label: uapi.BytesToString(ci.Label[:]),
|
||||
lines: int(ci.Lines),
|
||||
options: co,
|
||||
}
|
||||
if len(c.Label) == 0 {
|
||||
c.Label = "unknown"
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// Close releases the Chip.
|
||||
//
|
||||
// It does not release any lines which may be requested - they must be closed
|
||||
// independently.
|
||||
func (c *Chip) Close() error {
|
||||
c.mu.Lock()
|
||||
closed := c.closed
|
||||
c.closed = true
|
||||
c.mu.Unlock()
|
||||
if closed {
|
||||
return ErrClosed
|
||||
}
|
||||
if c.iw != nil {
|
||||
c.iw.close()
|
||||
}
|
||||
return c.f.Close()
|
||||
}
|
||||
|
||||
// FindLine returns the offset of the named line, or an error if not found.
|
||||
func (c *Chip) FindLine(name string) (int, error) {
|
||||
for o := 0; o < c.lines; o++ {
|
||||
inf, err := c.LineInfo(o)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if inf.Name == name {
|
||||
return o, nil
|
||||
}
|
||||
}
|
||||
return 0, ErrLineNotFound
|
||||
}
|
||||
|
||||
// FindLines returns the offsets of the named lines, or an error unless all are
|
||||
// found.
|
||||
func (c *Chip) FindLines(names ...string) (oo []int, err error) {
|
||||
ioo := make([]int, len(names))
|
||||
for i, name := range names {
|
||||
var o int
|
||||
o, err = c.FindLine(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ioo[i] = o
|
||||
}
|
||||
oo = ioo
|
||||
return
|
||||
}
|
||||
|
||||
// LineInfo returns the publically available information on the line.
|
||||
//
|
||||
// This is always available and does not require requesting the line.
|
||||
func (c *Chip) LineInfo(offset int) (info LineInfo, err error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.closed {
|
||||
err = ErrClosed
|
||||
return
|
||||
}
|
||||
if offset < 0 || offset >= c.lines {
|
||||
err = ErrInvalidOffset
|
||||
return
|
||||
}
|
||||
var li uapi.LineInfo
|
||||
li, err = uapi.GetLineInfo(c.f.Fd(), offset)
|
||||
if err == nil {
|
||||
info = newLineInfo(li)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func newLineInfo(li uapi.LineInfo) LineInfo {
|
||||
return LineInfo{
|
||||
Offset: int(li.Offset),
|
||||
Name: uapi.BytesToString(li.Name[:]),
|
||||
Consumer: uapi.BytesToString(li.Consumer[:]),
|
||||
Requested: li.Flags.IsRequested(),
|
||||
IsOut: li.Flags.IsOut(),
|
||||
ActiveLow: li.Flags.IsActiveLow(),
|
||||
OpenDrain: li.Flags.IsOpenDrain(),
|
||||
OpenSource: li.Flags.IsOpenSource(),
|
||||
BiasDisable: li.Flags.IsBiasDisable(),
|
||||
PullDown: li.Flags.IsPullDown(),
|
||||
PullUp: li.Flags.IsPullUp(),
|
||||
}
|
||||
}
|
||||
|
||||
// Lines returns the number of lines that exist on the GPIO chip.
|
||||
func (c *Chip) Lines() int {
|
||||
return c.lines
|
||||
}
|
||||
|
||||
// RequestLine requests control of a single line on the chip.
|
||||
//
|
||||
// If granted, control is maintained until either the Line or Chip are closed.
|
||||
func (c *Chip) RequestLine(offset int, options ...LineOption) (*Line, error) {
|
||||
ll, err := c.RequestLines([]int{offset}, options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := Line{baseLine{
|
||||
offsets: ll.offsets,
|
||||
vfd: ll.vfd,
|
||||
isEvent: ll.isEvent,
|
||||
chip: c.Name,
|
||||
flags: ll.flags,
|
||||
outputValues: ll.outputValues,
|
||||
w: ll.w,
|
||||
}}
|
||||
return &l, nil
|
||||
}
|
||||
|
||||
// RequestLines requests control of a collection of lines on the chip.
|
||||
func (c *Chip) RequestLines(offsets []int, options ...LineOption) (*Lines, error) {
|
||||
for _, o := range offsets {
|
||||
if o < 0 || o >= c.lines {
|
||||
return nil, ErrInvalidOffset
|
||||
}
|
||||
}
|
||||
lo := LineOptions{
|
||||
consumer: c.options.consumer,
|
||||
HandleFlags: c.options.HandleFlags,
|
||||
}
|
||||
for _, option := range options {
|
||||
option.applyLineOption(&lo)
|
||||
}
|
||||
ll := Lines{baseLine{
|
||||
offsets: append([]int(nil), offsets...),
|
||||
chip: c.Name,
|
||||
flags: lo.HandleFlags,
|
||||
outputValues: lo.InitialValues,
|
||||
}}
|
||||
var err error
|
||||
if lo.eh != nil {
|
||||
ll.isEvent = true
|
||||
ll.vfd, ll.w, err = c.getEventRequest(ll.offsets, lo)
|
||||
} else {
|
||||
ll.vfd, err = c.getHandleRequest(ll.offsets, lo)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ll, nil
|
||||
}
|
||||
|
||||
// creates the iw and ich
|
||||
//
|
||||
// Assumes c is locked.
|
||||
func (c *Chip) createInfoWatcher() error {
|
||||
iw, err := newInfoWatcher(int(c.f.Fd()),
|
||||
func(lic LineInfoChangeEvent) {
|
||||
c.mu.Lock()
|
||||
ich := c.ich[lic.Info.Offset]
|
||||
c.mu.Unlock() // handler called outside lock
|
||||
if ich != nil {
|
||||
ich(lic)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.iw = iw
|
||||
c.ich = map[int]InfoChangeHandler{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WatchLineInfo enables watching changes to line info for the specified lines.
|
||||
//
|
||||
// The changes are reported via the chip InfoChangeHandler.
|
||||
// Repeated calls replace the InfoChangeHandler.
|
||||
//
|
||||
// Requires Linux v5.7 or later.
|
||||
func (c *Chip) WatchLineInfo(offset int, lich InfoChangeHandler) (info LineInfo, err error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.closed {
|
||||
err = ErrClosed
|
||||
return
|
||||
}
|
||||
if c.iw == nil {
|
||||
err = c.createInfoWatcher()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
li := uapi.LineInfo{Offset: uint32(offset)}
|
||||
err = uapi.WatchLineInfo(c.f.Fd(), &li)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.ich[offset] = lich
|
||||
info = newLineInfo(li)
|
||||
return
|
||||
}
|
||||
|
||||
// UnwatchLineInfo disables watching changes to line info.
|
||||
//
|
||||
// Requires Linux v5.7 or later.
|
||||
func (c *Chip) UnwatchLineInfo(offset int) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.closed {
|
||||
return nil
|
||||
}
|
||||
delete(c.ich, offset)
|
||||
return uapi.UnwatchLineInfo(c.f.Fd(), uint32(offset))
|
||||
}
|
||||
|
||||
func (c *Chip) getEventRequest(offsets []int, lo LineOptions) (uintptr, *watcher, error) {
|
||||
var vfd uintptr
|
||||
fds := make(map[int]int)
|
||||
for i, o := range offsets {
|
||||
er := uapi.EventRequest{
|
||||
Offset: uint32(o),
|
||||
HandleFlags: lo.HandleFlags,
|
||||
EventFlags: lo.EventFlags,
|
||||
}
|
||||
copy(er.Consumer[:len(er.Consumer)-1], lo.consumer)
|
||||
err := uapi.GetLineEvent(c.f.Fd(), &er)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
fd := uintptr(er.Fd)
|
||||
if i == 0 {
|
||||
vfd = fd
|
||||
}
|
||||
fds[int(fd)] = o
|
||||
}
|
||||
w, err := newWatcher(fds, lo.eh)
|
||||
if err != nil {
|
||||
for fd := range fds {
|
||||
unix.Close(fd)
|
||||
}
|
||||
return 0, nil, err
|
||||
}
|
||||
return vfd, w, nil
|
||||
}
|
||||
|
||||
func (c *Chip) getHandleRequest(offsets []int, lo LineOptions) (uintptr, error) {
|
||||
hr := uapi.HandleRequest{
|
||||
Lines: uint32(len(offsets)),
|
||||
Flags: lo.HandleFlags,
|
||||
}
|
||||
copy(hr.Consumer[:len(hr.Consumer)-1], lo.consumer)
|
||||
// copy(hr.Offsets[:], offsets) - with cast
|
||||
for i, o := range offsets {
|
||||
hr.Offsets[i] = uint32(o)
|
||||
}
|
||||
// copy(hr.DefaultValues[:], lo.InitialValues) - with cast
|
||||
for i, v := range lo.InitialValues {
|
||||
hr.DefaultValues[i] = uint8(v)
|
||||
}
|
||||
err := uapi.GetLineHandle(c.f.Fd(), &hr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uintptr(hr.Fd), nil
|
||||
}
|
||||
|
||||
type baseLine struct {
|
||||
offsets []int
|
||||
vfd uintptr
|
||||
isEvent bool
|
||||
chip string
|
||||
// mu covers all that follow - those above are immutable
|
||||
mu sync.Mutex
|
||||
flags uapi.HandleFlag
|
||||
outputValues []int
|
||||
info []*LineInfo
|
||||
closed bool
|
||||
w *watcher
|
||||
}
|
||||
|
||||
// Chip returns the name of the chip from which the line was requested.
|
||||
func (l *baseLine) Chip() string {
|
||||
return l.chip
|
||||
}
|
||||
|
||||
// Close releases all resources held by the requested line.
|
||||
func (l *baseLine) Close() error {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if l.closed {
|
||||
return ErrClosed
|
||||
}
|
||||
l.closed = true
|
||||
if l.w != nil {
|
||||
l.w.close()
|
||||
} else {
|
||||
unix.Close(int(l.vfd))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reconfigure updates the configuration of the requested line(s).
|
||||
//
|
||||
// Configuration for options other than those passed in remain unchanged.
|
||||
//
|
||||
// Not valid for lines with edge detection enabled.
|
||||
//
|
||||
// Requires Linux v5.5 or later.
|
||||
func (l *baseLine) Reconfigure(options ...LineConfig) error {
|
||||
if l.isEvent {
|
||||
return ErrPermissionDenied
|
||||
}
|
||||
if len(options) == 0 {
|
||||
return nil
|
||||
}
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if l.closed {
|
||||
return ErrClosed
|
||||
}
|
||||
lo := LineOptions{
|
||||
HandleFlags: l.flags,
|
||||
InitialValues: l.outputValues,
|
||||
}
|
||||
for _, option := range options {
|
||||
option.applyLineConfig(&lo)
|
||||
}
|
||||
hc := uapi.HandleConfig{Flags: lo.HandleFlags}
|
||||
for i, v := range lo.InitialValues {
|
||||
hc.DefaultValues[i] = uint8(v)
|
||||
}
|
||||
err := uapi.SetLineConfig(l.vfd, &hc)
|
||||
if err == nil {
|
||||
l.flags = hc.Flags
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Line represents a single requested line.
|
||||
type Line struct {
|
||||
baseLine
|
||||
}
|
||||
|
||||
// Offset returns the offset of the line within the chip.
|
||||
func (l *Line) Offset() int {
|
||||
return l.offsets[0]
|
||||
}
|
||||
|
||||
// Info returns the information about the line.
|
||||
func (l *Line) Info() (info LineInfo, err error) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if l.closed {
|
||||
err = ErrClosed
|
||||
return
|
||||
}
|
||||
if l.info != nil {
|
||||
info = *l.info[0]
|
||||
return
|
||||
}
|
||||
c, err := NewChip(l.chip)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
inf, err := c.LineInfo(l.offsets[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
l.info = []*LineInfo{&inf}
|
||||
info = *l.info[0]
|
||||
return
|
||||
}
|
||||
|
||||
// Value returns the current value (active state) of the line.
|
||||
func (l *Line) Value() (int, error) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if l.closed {
|
||||
return 0, ErrClosed
|
||||
}
|
||||
var values uapi.HandleData
|
||||
err := uapi.GetLineValues(l.vfd, &values)
|
||||
return int(values[0]), err
|
||||
}
|
||||
|
||||
// SetValue sets the current active state of the line.
|
||||
//
|
||||
// Only valid for output lines.
|
||||
func (l *Line) SetValue(value int) error {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if !l.flags.IsOutput() {
|
||||
return ErrPermissionDenied
|
||||
}
|
||||
if l.closed {
|
||||
return ErrClosed
|
||||
}
|
||||
l.outputValues = []int{value}
|
||||
var values uapi.HandleData
|
||||
values[0] = uint8(value)
|
||||
return uapi.SetLineValues(l.vfd, values)
|
||||
}
|
||||
|
||||
// Lines represents a collection of requested lines.
|
||||
type Lines struct {
|
||||
baseLine
|
||||
}
|
||||
|
||||
// Offsets returns the offsets of the lines within the chip.
|
||||
func (l *Lines) Offsets() []int {
|
||||
return l.offsets
|
||||
}
|
||||
|
||||
// Info returns the information about the lines.
|
||||
func (l *Lines) Info() ([]*LineInfo, error) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if l.closed {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
if l.info != nil {
|
||||
return l.info, nil
|
||||
}
|
||||
c, err := NewChip(l.chip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer c.Close()
|
||||
info := make([]*LineInfo, len(l.offsets))
|
||||
for i, o := range l.offsets {
|
||||
inf, err := c.LineInfo(o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info[i] = &inf
|
||||
}
|
||||
l.info = info
|
||||
return l.info, nil
|
||||
}
|
||||
|
||||
// Values returns the current values (active state) of the collection of lines.
|
||||
//
|
||||
// Gets as many values from the set, in order, as can be fit in values, up to
|
||||
// the full set.
|
||||
func (l *Lines) Values(values []int) error {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if l.closed {
|
||||
return ErrClosed
|
||||
}
|
||||
var uvv uapi.HandleData
|
||||
err := uapi.GetLineValues(l.vfd, &uvv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := len(l.offsets)
|
||||
if len(values) < lines {
|
||||
lines = len(values)
|
||||
}
|
||||
for i := 0; i < lines; i++ {
|
||||
values[i] = int(uvv[i])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetValues sets the current active state of the collection of lines.
|
||||
//
|
||||
// Only valid for output lines.
|
||||
//
|
||||
// All lines in the set are set at once. If insufficient values are provided
|
||||
// then the remaining lines are set to inactive.
|
||||
func (l *Lines) SetValues(values []int) error {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if !l.flags.IsOutput() {
|
||||
return ErrPermissionDenied
|
||||
}
|
||||
if len(values) > len(l.offsets) {
|
||||
return ErrInvalidOffset
|
||||
}
|
||||
if l.closed {
|
||||
return ErrClosed
|
||||
}
|
||||
l.outputValues = append([]int(nil), values...)
|
||||
var vv uapi.HandleData
|
||||
for i, v := range values {
|
||||
vv[i] = uint8(v)
|
||||
}
|
||||
return uapi.SetLineValues(l.vfd, vv)
|
||||
}
|
||||
|
||||
// LineEventType indicates the type of change to the line active state.
|
||||
//
|
||||
// Note that for active low lines a low line level results in a high active
|
||||
// state.
|
||||
type LineEventType int
|
||||
|
||||
const (
|
||||
_ LineEventType = iota
|
||||
// LineEventRisingEdge indicates an inactive to active event.
|
||||
LineEventRisingEdge
|
||||
|
||||
// LineEventFallingEdge indicates an active to inactive event.
|
||||
LineEventFallingEdge
|
||||
)
|
||||
|
||||
// LineEvent represents a change in the state of a line.
|
||||
type LineEvent struct {
|
||||
// The line offset within the GPIO chip.
|
||||
Offset int
|
||||
|
||||
// Timestamp indicates the time the event was detected.
|
||||
//
|
||||
// The timestamp is intended for accurately measuring intervals between
|
||||
// events. It is not guaranteed to be based on a particular clock. It has
|
||||
// been based on CLOCK_REALTIME, but from Linux v5.7 it is based on
|
||||
// CLOCK_MONOTONIC.
|
||||
Timestamp time.Duration
|
||||
|
||||
// The type of state change event this structure represents.
|
||||
Type LineEventType
|
||||
}
|
||||
|
||||
// LineInfoChangeEvent represents a change in the info a line.
|
||||
type LineInfoChangeEvent struct {
|
||||
// Info is the updated line info.
|
||||
Info LineInfo
|
||||
|
||||
// Timestamp indicates the time the event was detected.
|
||||
//
|
||||
// The timestamp is intended for accurately measuring intervals between
|
||||
// events. It is not guaranteed to be based on a particular clock, but from
|
||||
// Linux v5.7 it is based on CLOCK_MONOTONIC.
|
||||
Timestamp time.Duration
|
||||
|
||||
// The type of info change event this structure represents.
|
||||
Type LineInfoChangeType
|
||||
}
|
||||
|
||||
// LineInfoChangeType indicates the type of change to the line info.
|
||||
type LineInfoChangeType int
|
||||
|
||||
const (
|
||||
_ LineInfoChangeType = iota
|
||||
|
||||
// LineRequested indicates the line has been requested.
|
||||
LineRequested
|
||||
|
||||
// LineReleased indicates the line has been released.
|
||||
LineReleased
|
||||
|
||||
// LineReconfigured indicates the line configuration has changed.
|
||||
LineReconfigured
|
||||
)
|
||||
|
||||
// InfoChangeHandler is a receiver for line info change events.
|
||||
type InfoChangeHandler func(LineInfoChangeEvent)
|
||||
|
||||
// IsChip checks if the named device is an accessible GPIO character device.
|
||||
//
|
||||
// Returns an error if not.
|
||||
func IsChip(name string) error {
|
||||
path := nameToPath(name)
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fi.Mode()&os.ModeCharDevice == 0 {
|
||||
return ErrNotCharacterDevice
|
||||
}
|
||||
sysfspath := fmt.Sprintf("/sys/bus/gpio/devices/%s/dev", fi.Name())
|
||||
if err = unix.Access(sysfspath, unix.R_OK); err != nil {
|
||||
return ErrNotCharacterDevice
|
||||
}
|
||||
sysfsf, err := os.Open(sysfspath)
|
||||
if err != nil {
|
||||
// changed since Access?
|
||||
return ErrNotCharacterDevice
|
||||
}
|
||||
var sysfsdev [16]byte
|
||||
n, err := sysfsf.Read(sysfsdev[:])
|
||||
sysfsf.Close()
|
||||
if err != nil || n <= 0 {
|
||||
return ErrNotCharacterDevice
|
||||
}
|
||||
var stat unix.Stat_t
|
||||
if err = unix.Lstat(path, &stat); err != nil {
|
||||
return err
|
||||
}
|
||||
devstr := fmt.Sprintf("%d:%d", unix.Major(uint64(stat.Rdev)), unix.Minor(uint64(stat.Rdev)))
|
||||
sysstr := string(sysfsdev[:n-1])
|
||||
if devstr != sysstr {
|
||||
return ErrNotCharacterDevice
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// chipNames returns the name of potential gpiochips.
|
||||
//
|
||||
// Does not open them or check if they are valid.
|
||||
func chipNames() []string {
|
||||
ee, err := ioutil.ReadDir("/dev")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
cc := []string(nil)
|
||||
for _, e := range ee {
|
||||
name := e.Name()
|
||||
if strings.HasPrefix(name, "gpiochip") {
|
||||
cc = append(cc, name)
|
||||
}
|
||||
}
|
||||
return cc
|
||||
}
|
||||
|
||||
// helper that finds the chip and offset corresponding to a named line.
|
||||
//
|
||||
// If found returns the chip and offset, else an error.
|
||||
func findLine(lname string) (*Chip, int, error) {
|
||||
for _, name := range chipNames() {
|
||||
c, err := NewChip(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
o, err := c.FindLine(lname)
|
||||
if err == nil {
|
||||
return c, o, nil
|
||||
}
|
||||
}
|
||||
return nil, 0, ErrLineNotFound
|
||||
}
|
||||
|
||||
func nameToPath(name string) string {
|
||||
if strings.HasPrefix(name, "/dev/") {
|
||||
return name
|
||||
}
|
||||
return "/dev/" + name
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrClosed indicates the chip or line has already been closed.
|
||||
ErrClosed = errors.New("already closed")
|
||||
|
||||
// ErrInvalidOffset indicates a line offset is invalid.
|
||||
ErrInvalidOffset = errors.New("invalid offset")
|
||||
|
||||
// ErrNotCharacterDevice indicates the device is not a character device.
|
||||
ErrNotCharacterDevice = errors.New("not a character device")
|
||||
|
||||
// ErrLineNotFound indicates the line was not found.
|
||||
ErrLineNotFound = errors.New("line not found")
|
||||
|
||||
// ErrPermissionDenied indicates caller does not have required permissions
|
||||
// for the operation.
|
||||
ErrPermissionDenied = errors.New("permission denied")
|
||||
)
|
111
vendor/github.com/warthog618/gpiod/infowatcher.go
generated
vendored
Normal file
111
vendor/github.com/warthog618/gpiod/infowatcher.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2020 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
package gpiod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/warthog618/gpiod/uapi"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type infoWatcher struct {
|
||||
epfd int
|
||||
|
||||
// the handler for detected events
|
||||
ch InfoChangeHandler
|
||||
|
||||
// pipe to signal watcher to shutdown
|
||||
donefds []int
|
||||
|
||||
// closed once watcher exits
|
||||
doneCh chan struct{}
|
||||
}
|
||||
|
||||
func newInfoWatcher(fd int, ch InfoChangeHandler) (iw *infoWatcher, err error) {
|
||||
var epfd int
|
||||
epfd, err = unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
unix.Close(epfd)
|
||||
}
|
||||
}()
|
||||
p := []int{0, 0}
|
||||
err = unix.Pipe2(p, unix.O_CLOEXEC)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
unix.Close(p[0])
|
||||
unix.Close(p[1])
|
||||
}
|
||||
}()
|
||||
epv := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(p[0])}
|
||||
err = unix.EpollCtl(epfd, unix.EPOLL_CTL_ADD, int(p[0]), &epv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
epv.Fd = int32(fd)
|
||||
err = unix.EpollCtl(epfd, unix.EPOLL_CTL_ADD, fd, &epv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
iw = &infoWatcher{
|
||||
epfd: epfd,
|
||||
ch: ch,
|
||||
donefds: p,
|
||||
doneCh: make(chan struct{}),
|
||||
}
|
||||
go iw.watch()
|
||||
return
|
||||
}
|
||||
|
||||
func (iw *infoWatcher) close() {
|
||||
unix.Write(iw.donefds[1], []byte("bye"))
|
||||
<-iw.doneCh
|
||||
unix.Close(iw.donefds[0])
|
||||
unix.Close(iw.donefds[1])
|
||||
}
|
||||
|
||||
func (iw *infoWatcher) watch() {
|
||||
epollEvents := make([]unix.EpollEvent, 2)
|
||||
defer close(iw.doneCh)
|
||||
for {
|
||||
n, err := unix.EpollWait(iw.epfd, epollEvents[:], -1)
|
||||
if err != nil {
|
||||
if err == unix.EBADF || err == unix.EINVAL {
|
||||
// fd closed so exit
|
||||
return
|
||||
}
|
||||
if err == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
panic(fmt.Sprintf("EpollWait unexpected error: %v", err))
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ev := epollEvents[i]
|
||||
fd := ev.Fd
|
||||
if fd == int32(iw.donefds[0]) {
|
||||
unix.Close(iw.epfd)
|
||||
return
|
||||
}
|
||||
lic, err := uapi.ReadLineInfoChanged(uintptr(fd))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
lice := LineInfoChangeEvent{
|
||||
Info: newLineInfo(lic.Info),
|
||||
Timestamp: time.Duration(lic.Timestamp),
|
||||
Type: LineInfoChangeType(lic.Type),
|
||||
}
|
||||
iw.ch(lice)
|
||||
}
|
||||
}
|
||||
}
|
293
vendor/github.com/warthog618/gpiod/options.go
generated
vendored
Normal file
293
vendor/github.com/warthog618/gpiod/options.go
generated
vendored
Normal file
|
@ -0,0 +1,293 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2019 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
package gpiod
|
||||
|
||||
import "github.com/warthog618/gpiod/uapi"
|
||||
|
||||
// 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
|
||||
HandleFlags uapi.HandleFlag
|
||||
}
|
||||
|
||||
// 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) applyLineOption(l *LineOptions) {
|
||||
l.consumer = string(o)
|
||||
}
|
||||
|
||||
// LineOption defines the interface required to provide an option for Line and
|
||||
// Lines.
|
||||
type LineOption interface {
|
||||
applyLineOption(*LineOptions)
|
||||
}
|
||||
|
||||
// LineConfig defines the interface required to update an option for Line and
|
||||
// Lines.
|
||||
type LineConfig interface {
|
||||
applyLineConfig(*LineOptions)
|
||||
}
|
||||
|
||||
// LineOptions contains the options for a Line or Lines.
|
||||
type LineOptions struct {
|
||||
consumer string
|
||||
InitialValues []int
|
||||
EventFlags uapi.EventFlag
|
||||
HandleFlags uapi.HandleFlag
|
||||
eh EventHandler
|
||||
}
|
||||
|
||||
// EventHandler is a receiver for line events.
|
||||
type EventHandler func(LineEvent)
|
||||
|
||||
// AsIsOption indicates the line direction should be left as is.
|
||||
type AsIsOption struct{}
|
||||
|
||||
// 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.
|
||||
var AsIs = AsIsOption{}
|
||||
|
||||
func (o AsIsOption) applyLineOption(l *LineOptions) {
|
||||
l.HandleFlags &= ^(uapi.HandleRequestOutput | uapi.HandleRequestInput)
|
||||
}
|
||||
|
||||
// InputOption indicates the line direction should be set to an input.
|
||||
type InputOption struct{}
|
||||
|
||||
// AsInput indicates that a line be requested as an input.
|
||||
//
|
||||
// This option overrides and clears any previous Output, OpenDrain, or
|
||||
// OpenSource options.
|
||||
var AsInput = InputOption{}
|
||||
|
||||
func (o InputOption) updateFlags(f uapi.HandleFlag) uapi.HandleFlag {
|
||||
f &= ^(uapi.HandleRequestOutput |
|
||||
uapi.HandleRequestOpenDrain |
|
||||
uapi.HandleRequestOpenSource)
|
||||
f |= uapi.HandleRequestInput
|
||||
return f
|
||||
}
|
||||
|
||||
func (o InputOption) applyChipOption(c *ChipOptions) {
|
||||
c.HandleFlags = o.updateFlags(c.HandleFlags)
|
||||
}
|
||||
|
||||
func (o InputOption) applyLineOption(l *LineOptions) {
|
||||
l.HandleFlags = o.updateFlags(l.HandleFlags)
|
||||
}
|
||||
|
||||
func (o InputOption) applyLineConfig(l *LineOptions) {
|
||||
o.applyLineOption(l)
|
||||
}
|
||||
|
||||
// OutputOption indicates the line direction should be set to an output.
|
||||
type OutputOption struct {
|
||||
initialValues []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,
|
||||
// or BothEdges options.
|
||||
func AsOutput(values ...int) OutputOption {
|
||||
vv := append([]int(nil), values...)
|
||||
return OutputOption{vv}
|
||||
}
|
||||
|
||||
func (o OutputOption) applyLineOption(l *LineOptions) {
|
||||
l.HandleFlags &= ^uapi.HandleRequestInput
|
||||
l.HandleFlags |= uapi.HandleRequestOutput
|
||||
l.EventFlags = 0
|
||||
l.InitialValues = o.initialValues
|
||||
}
|
||||
|
||||
func (o OutputOption) applyLineConfig(l *LineOptions) {
|
||||
o.applyLineOption(l)
|
||||
}
|
||||
|
||||
// LevelOption determines the line level that is considered active.
|
||||
type LevelOption struct {
|
||||
flag uapi.HandleFlag
|
||||
}
|
||||
|
||||
func (o LevelOption) updateFlags(f uapi.HandleFlag) uapi.HandleFlag {
|
||||
f &= ^uapi.HandleRequestActiveLow
|
||||
f |= o.flag
|
||||
return f
|
||||
}
|
||||
|
||||
func (o LevelOption) applyChipOption(c *ChipOptions) {
|
||||
c.HandleFlags = o.updateFlags(c.HandleFlags)
|
||||
}
|
||||
|
||||
func (o LevelOption) applyLineOption(l *LineOptions) {
|
||||
l.HandleFlags = o.updateFlags(l.HandleFlags)
|
||||
}
|
||||
|
||||
func (o LevelOption) applyLineConfig(l *LineOptions) {
|
||||
o.applyLineOption(l)
|
||||
}
|
||||
|
||||
// AsActiveLow indicates that a line be considered active when the line level
|
||||
// is low.
|
||||
var AsActiveLow = LevelOption{uapi.HandleRequestActiveLow}
|
||||
|
||||
// AsActiveHigh indicates that a line be considered active when the line level
|
||||
// is high.
|
||||
//
|
||||
// This is the default active level.
|
||||
var AsActiveHigh = LevelOption{}
|
||||
|
||||
// DriveOption determines if a line is open drain, open source or push-pull.
|
||||
type DriveOption struct {
|
||||
flag uapi.HandleFlag
|
||||
}
|
||||
|
||||
func (o DriveOption) applyLineOption(l *LineOptions) {
|
||||
l.HandleFlags &= ^(uapi.HandleRequestInput |
|
||||
uapi.HandleRequestOpenDrain |
|
||||
uapi.HandleRequestOpenSource)
|
||||
l.HandleFlags |= (o.flag | uapi.HandleRequestOutput)
|
||||
l.EventFlags = 0
|
||||
}
|
||||
|
||||
func (o DriveOption) applyLineConfig(l *LineOptions) {
|
||||
o.applyLineOption(l)
|
||||
}
|
||||
|
||||
// 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, or OpenSource options.
|
||||
var AsOpenDrain = DriveOption{uapi.HandleRequestOpenDrain}
|
||||
|
||||
// AsOpenSource 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, or OpenDrain options.
|
||||
var AsOpenSource = DriveOption{uapi.HandleRequestOpenSource}
|
||||
|
||||
// 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, or OpenSource options.
|
||||
var AsPushPull = DriveOption{}
|
||||
|
||||
// BiasOption indicates how a line is to be biased.
|
||||
//
|
||||
// Bias options require Linux v5.5 or later.
|
||||
type BiasOption struct {
|
||||
flag uapi.HandleFlag
|
||||
}
|
||||
|
||||
func (o BiasOption) updateFlags(f uapi.HandleFlag) uapi.HandleFlag {
|
||||
f &= ^(uapi.HandleRequestBiasDisable |
|
||||
uapi.HandleRequestPullDown |
|
||||
uapi.HandleRequestPullUp)
|
||||
f |= o.flag
|
||||
return f
|
||||
}
|
||||
|
||||
func (o BiasOption) applyChipOption(c *ChipOptions) {
|
||||
c.HandleFlags = o.updateFlags(c.HandleFlags)
|
||||
}
|
||||
|
||||
func (o BiasOption) applyLineOption(l *LineOptions) {
|
||||
l.HandleFlags = o.updateFlags(l.HandleFlags)
|
||||
}
|
||||
|
||||
func (o BiasOption) applyLineConfig(l *LineOptions) {
|
||||
o.applyLineOption(l)
|
||||
}
|
||||
|
||||
// WithBiasDisable indicates that a line have its internal bias disabled.
|
||||
//
|
||||
// This option overrides and clears any previous bias options.
|
||||
//
|
||||
// Requires Linux v5.5 or later.
|
||||
var WithBiasDisable = BiasOption{uapi.HandleRequestBiasDisable}
|
||||
|
||||
// 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.
|
||||
var WithPullDown = BiasOption{uapi.HandleRequestPullDown}
|
||||
|
||||
// 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.
|
||||
var WithPullUp = BiasOption{uapi.HandleRequestPullUp}
|
||||
|
||||
// EdgeOption indicates that a line will generate events when edges are detected.
|
||||
type EdgeOption struct {
|
||||
e EventHandler
|
||||
edge uapi.EventFlag
|
||||
}
|
||||
|
||||
func (o EdgeOption) applyLineOption(l *LineOptions) {
|
||||
l.HandleFlags &= ^(uapi.HandleRequestOutput |
|
||||
uapi.HandleRequestOpenDrain |
|
||||
uapi.HandleRequestOpenSource)
|
||||
l.HandleFlags |= uapi.HandleRequestInput
|
||||
l.EventFlags = o.edge
|
||||
l.eh = o.e
|
||||
}
|
||||
|
||||
// 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.
|
||||
func WithFallingEdge(e func(LineEvent)) EdgeOption {
|
||||
return EdgeOption{EventHandler(e), uapi.EventRequestFallingEdge}
|
||||
}
|
||||
|
||||
// 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.
|
||||
func WithRisingEdge(e func(LineEvent)) EdgeOption {
|
||||
return EdgeOption{EventHandler(e), uapi.EventRequestRisingEdge}
|
||||
}
|
||||
|
||||
// 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.
|
||||
func WithBothEdges(e func(LineEvent)) EdgeOption {
|
||||
return EdgeOption{EventHandler(e), uapi.EventRequestBothEdges}
|
||||
}
|
75
vendor/github.com/warthog618/gpiod/uapi/README.md
generated
vendored
Normal file
75
vendor/github.com/warthog618/gpiod/uapi/README.md
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
# uapi
|
||||
|
||||
[](https://godoc.org/github.com/warthog618/gpiod/uapi)
|
||||
[](https://github.com/warthog618/gpiod/blob/master/LICENSE)
|
||||
|
||||
GPIOD UAPI is a thin layer over the system ioctl calls that comprise the Linux GPIO UAPI.
|
||||
|
||||
This library is used by **[gpiod](https://github.com/warthog618/gpiod)** to interact with the Linux kernel.
|
||||
|
||||
The library is exposed to allow for testing of the UAPI with the minimal amount of Go in the way.
|
||||
|
||||
**gpiod** provides a higher level of abstraction, so for general use you probably want to be using that.
|
||||
|
||||
## API
|
||||
|
||||
The GPIO UAPI comprises six ioctls:
|
||||
|
||||
IOCTL | Scope | Description
|
||||
---|--- | ---
|
||||
[GetChipInfo](https://godoc.org/github.com/warthog618/gpiod/uapi#GetChipInfo) | chip | Returns information about the chip itself.
|
||||
[GetLineInfo](https://godoc.org/github.com/warthog618/gpiod/uapi#GetLineInfo) | chip | Returns information about a particular line on the chip.
|
||||
[GetLineHandle](https://godoc.org/github.com/warthog618/gpiod/uapi#GetLineHandle) | chip | Requests a set of lines, and returns a file handle for ioctl commands. The set may be any subset of the lines supported by the chip, including a single line. This may be used for both input and output lines. The lines remain reserved by the caller until the returned fd is closed.
|
||||
[GetLineEvent](https://godoc.org/github.com/warthog618/gpiod/uapi#GetLineEvent) | chip | Requests an individual input line with edge detection enabled, and returns a file handle for ioctl commands and to return edge events. Events can only be requested on input lines. The line remains reserved by the caller until the returned fd is closed.
|
||||
[GetLineValues](https://godoc.org/github.com/warthog618/gpiod/uapi#GetLineValues) | line | Returns the current value of a set of lines.
|
||||
[SetLineValues](https://godoc.org/github.com/warthog618/gpiod/uapi#SetLineValues) | line | Sets the current value of a set of lines.
|
||||
|
||||
## Usage
|
||||
|
||||
The following is a brief example of the usage of each of the major functions:
|
||||
|
||||
```go
|
||||
f, _ := os.OpenFile("/dev/gpiochip0", unix.O_CLOEXEC, unix.O_RDONLY)
|
||||
|
||||
// get chip info
|
||||
ci, _ := uapi.GetChipInfo(f.Fd())
|
||||
|
||||
// get line info
|
||||
li, _ := uapi.GetLineInfo(f.Fd(), offset)
|
||||
|
||||
// request a line
|
||||
hr := uapi.HandleRequest{
|
||||
Lines: uint32(len(offsets)),
|
||||
Flags: handleFlags,
|
||||
// initialise Offsets, DefaultValues and Consumer...
|
||||
}
|
||||
err := uapi.GetLineHandle(f.Fd(), &hr)
|
||||
|
||||
// request a line with events
|
||||
er := uapi.EventRequest{
|
||||
Offset: offset,
|
||||
HandleFlags: handleFlags,
|
||||
EventFlags: eventFlags,
|
||||
// initialise Consumer...
|
||||
}
|
||||
err := uapi.GetLineEvent(f.Fd(), &er)
|
||||
if err != nil {
|
||||
// wait on er.fd for events...
|
||||
|
||||
// read event
|
||||
evt, _ := uapi.ReadEvent(er.fd)
|
||||
}
|
||||
|
||||
// get values
|
||||
var values uapi.HandleData
|
||||
_ := uapi.GetLineValues(er.fd, &values)
|
||||
|
||||
// set values
|
||||
values[0] = uint8(value)
|
||||
_ := uapi.SetLineValues(hr.fd, values)
|
||||
|
||||
```
|
||||
|
||||
Error handling and other tedious bits, such as initialising the arrays in the requests, omitted for brevity.
|
||||
|
||||
Refer to **[gpiod](https://github.com/warthog618/gpiod)** for a concrete example of uapi usage.
|
31
vendor/github.com/warthog618/gpiod/uapi/endian.go
generated
vendored
Normal file
31
vendor/github.com/warthog618/gpiod/uapi/endian.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2019 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
// don't build on platforms with fixed endianness
|
||||
// +build !amd64
|
||||
// +build !386
|
||||
|
||||
package uapi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// endian to use to decode reads from the local kernel.
|
||||
var nativeEndian binary.ByteOrder
|
||||
|
||||
func init() {
|
||||
// the standard hack to determine native Endianness.
|
||||
buf := [2]byte{}
|
||||
*(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xABCD)
|
||||
switch buf {
|
||||
case [2]byte{0xCD, 0xAB}:
|
||||
nativeEndian = binary.LittleEndian
|
||||
case [2]byte{0xAB, 0xCD}:
|
||||
nativeEndian = binary.BigEndian
|
||||
default:
|
||||
panic("Could not determine native endianness.")
|
||||
}
|
||||
}
|
14
vendor/github.com/warthog618/gpiod/uapi/endian_intel.go
generated
vendored
Normal file
14
vendor/github.com/warthog618/gpiod/uapi/endian_intel.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2019 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
// +build 386 amd64
|
||||
|
||||
package uapi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// endian to use to decode reads from the local kernel.
|
||||
var nativeEndian binary.ByteOrder = binary.LittleEndian
|
30
vendor/github.com/warthog618/gpiod/uapi/ioctl.go
generated
vendored
Normal file
30
vendor/github.com/warthog618/gpiod/uapi/ioctl.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2020 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
// +build linux
|
||||
|
||||
package uapi
|
||||
|
||||
// ioctl constants defined in ioctl_XXX
|
||||
|
||||
func ior(t, nr, size uintptr) ioctl {
|
||||
return ioctl((iocRead << iocDirShift) |
|
||||
(size << iocSizeShift) |
|
||||
(t << iocTypeShift) |
|
||||
(nr << iocNRShift))
|
||||
}
|
||||
|
||||
func iorw(t, nr, size uintptr) ioctl {
|
||||
return ioctl(((iocRead | iocWrite) << iocDirShift) |
|
||||
(size << iocSizeShift) |
|
||||
(t << iocTypeShift) |
|
||||
(nr << iocNRShift))
|
||||
}
|
||||
|
||||
func iow(t, nr, size uintptr) ioctl {
|
||||
return ioctl((iocWrite << iocDirShift) |
|
||||
(size << iocSizeShift) |
|
||||
(t << iocTypeShift) |
|
||||
(nr << iocNRShift))
|
||||
}
|
21
vendor/github.com/warthog618/gpiod/uapi/ioctl_default.go
generated
vendored
Normal file
21
vendor/github.com/warthog618/gpiod/uapi/ioctl_default.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2020 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
// +build arm arm64 386 amd64
|
||||
|
||||
package uapi
|
||||
|
||||
// ioctl constants
|
||||
const (
|
||||
iocNRBits = 8
|
||||
iocTypeBits = 8
|
||||
iocDirBits = 2
|
||||
iocSizeBits = 14
|
||||
iocNRShift = 0
|
||||
iocTypeShift = iocNRShift + iocNRBits
|
||||
iocSizeShift = iocTypeShift + iocTypeBits
|
||||
iocDirShift = iocSizeShift + iocSizeBits
|
||||
iocWrite = 1
|
||||
iocRead = 2
|
||||
)
|
22
vendor/github.com/warthog618/gpiod/uapi/ioctl_mips32.go
generated
vendored
Normal file
22
vendor/github.com/warthog618/gpiod/uapi/ioctl_mips32.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2020 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
// +build mips mipsle mips64 mips64le ppc64 ppc64le sparc sparc64
|
||||
|
||||
package uapi
|
||||
|
||||
// ioctl constants
|
||||
const (
|
||||
iocNRBits = 8
|
||||
iocTypeBits = 8
|
||||
iocDirBits = 3
|
||||
iocSizeBits = 13
|
||||
iocNRShift = 0
|
||||
iocTypeShift = iocNRShift + iocNRBits
|
||||
iocSizeShift = iocTypeShift + iocTypeBits
|
||||
iocDirShift = iocSizeShift + iocSizeBits
|
||||
iocWrite = 4
|
||||
iocRead = 2
|
||||
// iocNone = 1
|
||||
)
|
570
vendor/github.com/warthog618/gpiod/uapi/uapi.go
generated
vendored
Normal file
570
vendor/github.com/warthog618/gpiod/uapi/uapi.go
generated
vendored
Normal file
|
@ -0,0 +1,570 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2019 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
// +build linux
|
||||
|
||||
// Package uapi provides the Linux GPIO UAPI definitions for gpiod.
|
||||
package uapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// GetChipInfo returns the ChipInfo for the GPIO character device.
|
||||
//
|
||||
// The fd is an open GPIO character device.
|
||||
func GetChipInfo(fd uintptr) (ChipInfo, error) {
|
||||
var ci ChipInfo
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(getChipInfoIoctl),
|
||||
uintptr(unsafe.Pointer(&ci)))
|
||||
if errno != 0 {
|
||||
return ci, errno
|
||||
}
|
||||
return ci, nil
|
||||
}
|
||||
|
||||
// GetLineInfo returns the LineInfo for one line from the GPIO character device.
|
||||
//
|
||||
// The fd is an open GPIO character device.
|
||||
// The offset is zero based.
|
||||
func GetLineInfo(fd uintptr, offset int) (LineInfo, error) {
|
||||
var li LineInfo
|
||||
li.Offset = uint32(offset)
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(getLineInfoIoctl),
|
||||
uintptr(unsafe.Pointer(&li)))
|
||||
if errno != 0 {
|
||||
return LineInfo{}, errno
|
||||
}
|
||||
return li, nil
|
||||
}
|
||||
|
||||
// GetLineEvent requests a line from the GPIO character device with event
|
||||
// reporting enabled.
|
||||
//
|
||||
// The fd is an open GPIO character device.
|
||||
// The line must be an input and must not already be requested.
|
||||
// If successful, the fd for the line is returned in the request.fd.
|
||||
func GetLineEvent(fd uintptr, request *EventRequest) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(getLineEventIoctl),
|
||||
uintptr(unsafe.Pointer(request)))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLineHandle requests a line from the GPIO character device.
|
||||
//
|
||||
// This request is without event reporting.
|
||||
// The fd is an open GPIO character device.
|
||||
// The lines must not already be requested.
|
||||
// The flags in the request will be applied to all lines in the request.
|
||||
// If successful, the fd for the line is returned in the request.fd.
|
||||
func GetLineHandle(fd uintptr, request *HandleRequest) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(getLineHandleIoctl),
|
||||
uintptr(unsafe.Pointer(request)))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLineValues returns the values of a set of requested lines.
|
||||
//
|
||||
// The fd is a requested line, as returned by GetLineHandle or GetLineEvent.
|
||||
func GetLineValues(fd uintptr, values *HandleData) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(getLineValuesIoctl),
|
||||
uintptr(unsafe.Pointer(&values[0])))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLineValues sets the values of a set of requested lines.
|
||||
//
|
||||
// The fd is a requested line, as returned by GetLineHandle or GetLineEvent.
|
||||
func SetLineValues(fd uintptr, values HandleData) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(setLineValuesIoctl),
|
||||
uintptr(unsafe.Pointer(&values[0])))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLineConfig sets the config of an existing handle request.
|
||||
//
|
||||
// The config flags in the request will be applied to all lines in the handle
|
||||
// request.
|
||||
func SetLineConfig(fd uintptr, config *HandleConfig) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(setLineConfigIoctl),
|
||||
uintptr(unsafe.Pointer(config)))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WatchLineInfo sets a watch on info of a line.
|
||||
//
|
||||
// A watch is set on the line indicated by info.Offset. If successful the
|
||||
// current line info is returned, else an error is returned.
|
||||
func WatchLineInfo(fd uintptr, info *LineInfo) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(watchLineInfoIoctl),
|
||||
uintptr(unsafe.Pointer(info)))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnwatchLineInfo clears a watch on info of a line.
|
||||
//
|
||||
// Disables the watch on info for the line.
|
||||
func UnwatchLineInfo(fd uintptr, offset uint32) error {
|
||||
_, _, errno := unix.Syscall(unix.SYS_IOCTL,
|
||||
fd,
|
||||
uintptr(unwatchLineInfoIoctl),
|
||||
uintptr(unsafe.Pointer(&offset)))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BytesToString is a helper function that converts strings stored in byte
|
||||
// arrays, as returned by GetChipInfo and GetLineInfo, into strings.
|
||||
func BytesToString(a []byte) string {
|
||||
n := bytes.IndexByte(a, 0)
|
||||
if n == -1 {
|
||||
return string(a)
|
||||
}
|
||||
return string(a[:n])
|
||||
}
|
||||
|
||||
type fdReader int
|
||||
|
||||
func (fd fdReader) Read(b []byte) (int, error) {
|
||||
return unix.Read(int(fd), b[:])
|
||||
}
|
||||
|
||||
// ReadEvent reads a single event from a requested line.
|
||||
//
|
||||
// The fd is a requested line, as returned by GetLineEvent.
|
||||
//
|
||||
// This function is blocking and should only be called when the fd is known to
|
||||
// be ready to read.
|
||||
func ReadEvent(fd uintptr) (EventData, error) {
|
||||
var ed EventData
|
||||
err := binary.Read(fdReader(fd), nativeEndian, &ed)
|
||||
return ed, err
|
||||
}
|
||||
|
||||
// ReadLineInfoChanged reads a line info changed event from a chip.
|
||||
//
|
||||
// The fd is an open GPIO character device.
|
||||
//
|
||||
// This function is blocking and should only be called when the fd is known to
|
||||
// be ready to read.
|
||||
func ReadLineInfoChanged(fd uintptr) (LineInfoChanged, error) {
|
||||
var lic LineInfoChanged
|
||||
err := binary.Read(fdReader(fd), nativeEndian, &lic)
|
||||
return lic, err
|
||||
}
|
||||
|
||||
// IOCTL command codes
|
||||
type ioctl uintptr
|
||||
|
||||
var (
|
||||
getChipInfoIoctl ioctl
|
||||
getLineInfoIoctl ioctl
|
||||
getLineHandleIoctl ioctl
|
||||
getLineEventIoctl ioctl
|
||||
getLineValuesIoctl ioctl
|
||||
setLineValuesIoctl ioctl
|
||||
setLineConfigIoctl ioctl
|
||||
watchLineInfoIoctl ioctl
|
||||
unwatchLineInfoIoctl ioctl
|
||||
)
|
||||
|
||||
// Size of name and consumer strings.
|
||||
const nameSize = 32
|
||||
|
||||
func init() {
|
||||
// ioctls require struct sizes which are only available at runtime.
|
||||
var ci ChipInfo
|
||||
getChipInfoIoctl = ior(0xB4, 0x01, unsafe.Sizeof(ci))
|
||||
var li LineInfo
|
||||
getLineInfoIoctl = iorw(0xB4, 0x02, unsafe.Sizeof(li))
|
||||
var hr HandleRequest
|
||||
getLineHandleIoctl = iorw(0xB4, 0x03, unsafe.Sizeof(hr))
|
||||
var le EventRequest
|
||||
getLineEventIoctl = iorw(0xB4, 0x04, unsafe.Sizeof(le))
|
||||
var hd HandleData
|
||||
getLineValuesIoctl = iorw(0xB4, 0x08, unsafe.Sizeof(hd))
|
||||
setLineValuesIoctl = iorw(0xB4, 0x09, unsafe.Sizeof(hd))
|
||||
var hc HandleConfig
|
||||
setLineConfigIoctl = iorw(0xB4, 0x0a, unsafe.Sizeof(hc))
|
||||
watchLineInfoIoctl = iorw(0xB4, 0x0b, unsafe.Sizeof(li))
|
||||
unwatchLineInfoIoctl = iorw(0xB4, 0x0c, unsafe.Sizeof(li.Offset))
|
||||
}
|
||||
|
||||
// ChipInfo contains the details of a GPIO chip.
|
||||
type ChipInfo struct {
|
||||
// The system name of the device.
|
||||
Name [nameSize]byte
|
||||
|
||||
// An identifying label added by the device driver.
|
||||
Label [nameSize]byte
|
||||
|
||||
// The number of lines supported by this chip.
|
||||
Lines uint32
|
||||
}
|
||||
|
||||
// LineInfo contains the details of a single line of a GPIO chip.
|
||||
type LineInfo struct {
|
||||
// The offset of the line within the chip.
|
||||
Offset uint32
|
||||
|
||||
// The line flags applied to this line.
|
||||
Flags LineFlag
|
||||
|
||||
// The system name for this line.
|
||||
Name [nameSize]byte
|
||||
|
||||
// If requested, a string added by the requester to identify the
|
||||
// owner of the request.
|
||||
Consumer [nameSize]byte
|
||||
}
|
||||
|
||||
// LineInfoChanged contains the details of a change to line info.
|
||||
//
|
||||
// This is returned via the chip fd in response to changes to watched lines.
|
||||
type LineInfoChanged struct {
|
||||
// The updated info.
|
||||
Info LineInfo
|
||||
|
||||
// The time the change occured.
|
||||
Timestamp uint64
|
||||
|
||||
// The type of change.
|
||||
Type ChangeType
|
||||
|
||||
// reserved for future use.
|
||||
_ [5]uint32
|
||||
}
|
||||
|
||||
// ChangeType indicates the type of change that has occured to a line.
|
||||
type ChangeType uint32
|
||||
|
||||
const (
|
||||
_ ChangeType = iota
|
||||
|
||||
// LineChangedRequested indicates the line has been requested.
|
||||
LineChangedRequested
|
||||
|
||||
// LineChangedReleased indicates the line has been released.
|
||||
LineChangedReleased
|
||||
|
||||
// LineChangedConfig indicates the line configuration has changed.
|
||||
LineChangedConfig
|
||||
)
|
||||
|
||||
// LineFlag are the flags for a line.
|
||||
type LineFlag uint32
|
||||
|
||||
const (
|
||||
// LineFlagRequested indicates that the line has been requested.
|
||||
// It may have been requested by this process or another process.
|
||||
// The line cannot be requested again until this flag is clear.
|
||||
LineFlagRequested LineFlag = 1 << iota
|
||||
|
||||
// LineFlagIsOut indicates that the line is an output.
|
||||
LineFlagIsOut
|
||||
|
||||
// LineFlagActiveLow indicates that the line is active low.
|
||||
LineFlagActiveLow
|
||||
|
||||
// LineFlagOpenDrain indicates that the line will pull low when set low but
|
||||
// float when set high. This flag only applies to output lines.
|
||||
// An output cannot be both open drain and open source.
|
||||
LineFlagOpenDrain
|
||||
|
||||
// LineFlagOpenSource indicates that the line will pull high when set high
|
||||
// but float when set low. This flag only applies to output lines.
|
||||
// An output cannot be both open drain and open source.
|
||||
LineFlagOpenSource
|
||||
|
||||
// LineFlagPullUp indicates that the internal line pull up is enabled.
|
||||
LineFlagPullUp
|
||||
|
||||
// LineFlagPullDown indicates that the internal line pull down is enabled.
|
||||
LineFlagPullDown
|
||||
|
||||
// LineFlagBiasDisable indicates that the internal line bias is disabled.
|
||||
LineFlagBiasDisable
|
||||
)
|
||||
|
||||
// IsRequested returns true if the line is requested.
|
||||
func (f LineFlag) IsRequested() bool {
|
||||
return f&LineFlagRequested != 0
|
||||
}
|
||||
|
||||
// IsOut returns true if the line is an output.
|
||||
func (f LineFlag) IsOut() bool {
|
||||
return f&LineFlagIsOut != 0
|
||||
}
|
||||
|
||||
// IsActiveLow returns true if the line is active low.
|
||||
func (f LineFlag) IsActiveLow() bool {
|
||||
return f&LineFlagActiveLow != 0
|
||||
}
|
||||
|
||||
// IsOpenDrain returns true if the line is open-drain.
|
||||
func (f LineFlag) IsOpenDrain() bool {
|
||||
return f&LineFlagOpenDrain != 0
|
||||
}
|
||||
|
||||
// IsOpenSource returns true if the line is open-source.
|
||||
func (f LineFlag) IsOpenSource() bool {
|
||||
return f&LineFlagOpenSource != 0
|
||||
}
|
||||
|
||||
// IsBiasDisable returns true if the line has bias disabled.
|
||||
func (f LineFlag) IsBiasDisable() bool {
|
||||
return f&LineFlagBiasDisable != 0
|
||||
}
|
||||
|
||||
// IsPullDown returns true if the line has pull-down enabled.
|
||||
func (f LineFlag) IsPullDown() bool {
|
||||
return f&LineFlagPullDown != 0
|
||||
}
|
||||
|
||||
// IsPullUp returns true if the line has pull-up enabled.
|
||||
func (f LineFlag) IsPullUp() bool {
|
||||
return f&LineFlagPullUp != 0
|
||||
}
|
||||
|
||||
// HandleConfig is a request to change the config of an existing request.
|
||||
//
|
||||
// Can be applied to both handle and event requests.
|
||||
// Event requests cannot be reconfigured to outputs.
|
||||
type HandleConfig struct {
|
||||
// The flags to be applied to the lines.
|
||||
Flags HandleFlag
|
||||
|
||||
// The default values to be applied to output lines (when
|
||||
// HandleRequestOutput is set in the Flags).
|
||||
DefaultValues [HandlesMax]uint8
|
||||
|
||||
// reserved for future use.
|
||||
_ [4]uint32
|
||||
}
|
||||
|
||||
// HandleRequest is a request for control of a set of lines.
|
||||
// The lines must all be on the same GPIO chip.
|
||||
type HandleRequest struct {
|
||||
// The lines to be requested.
|
||||
Offsets [HandlesMax]uint32
|
||||
|
||||
// The flags to be applied to the lines.
|
||||
Flags HandleFlag
|
||||
|
||||
// The default values to be applied to output lines.
|
||||
DefaultValues [HandlesMax]uint8
|
||||
|
||||
// The string identifying the requester to be applied to the lines.
|
||||
Consumer [nameSize]byte
|
||||
|
||||
// The number of lines being requested.
|
||||
Lines uint32
|
||||
|
||||
// The file handle for the requested lines.
|
||||
// Set if the request is successful.
|
||||
Fd int32
|
||||
}
|
||||
|
||||
// HandleFlag contains the
|
||||
type HandleFlag uint32
|
||||
|
||||
const (
|
||||
// HandleRequestInput requests the line as an input.
|
||||
//
|
||||
// This is ignored if Output is also set.
|
||||
HandleRequestInput HandleFlag = 1 << iota
|
||||
|
||||
// HandleRequestOutput requests the line as an output.
|
||||
//
|
||||
// This takes precedence over Input, if both are set.
|
||||
HandleRequestOutput
|
||||
|
||||
// HandleRequestActiveLow requests the line be made active low.
|
||||
HandleRequestActiveLow
|
||||
|
||||
// HandleRequestOpenDrain requests the line be made open drain.
|
||||
//
|
||||
// This option requires the line to be requested as an Output.
|
||||
// This cannot be set at the same time as OpenSource.
|
||||
HandleRequestOpenDrain
|
||||
|
||||
// HandleRequestOpenSource requests the line be made open source.
|
||||
//
|
||||
// This option requires the line to be requested as an Output.
|
||||
// This cannot be set at the same time as OpenDrain.
|
||||
HandleRequestOpenSource
|
||||
|
||||
// HandleRequestPullUp requests the line have pull-up enabled.
|
||||
HandleRequestPullUp
|
||||
|
||||
// HandleRequestPullDown requests the line have pull-down enabled.
|
||||
HandleRequestPullDown
|
||||
|
||||
// HandleRequestBiasDisable requests the line have bias disabled.
|
||||
HandleRequestBiasDisable
|
||||
|
||||
// HandlesMax is the maximum number of lines that can be requested in a
|
||||
// single request.
|
||||
HandlesMax = 64
|
||||
)
|
||||
|
||||
// IsInput returns true if the line is requested as an input.
|
||||
func (f HandleFlag) IsInput() bool {
|
||||
return f&HandleRequestInput != 0
|
||||
}
|
||||
|
||||
// IsOutput returns true if the line is requested as an output.
|
||||
func (f HandleFlag) IsOutput() bool {
|
||||
return f&HandleRequestOutput != 0
|
||||
}
|
||||
|
||||
// IsActiveLow returns true if the line is requested as a active low.
|
||||
func (f HandleFlag) IsActiveLow() bool {
|
||||
return f&HandleRequestActiveLow != 0
|
||||
}
|
||||
|
||||
// IsOpenDrain returns true if the line is requested as an open drain.
|
||||
func (f HandleFlag) IsOpenDrain() bool {
|
||||
return f&HandleRequestOpenDrain != 0
|
||||
}
|
||||
|
||||
// IsOpenSource returns true if the line is requested as an open source.
|
||||
func (f HandleFlag) IsOpenSource() bool {
|
||||
return f&HandleRequestOpenSource != 0
|
||||
}
|
||||
|
||||
// IsBiasDisable returns true if the line is requested with bias disabled.
|
||||
func (f HandleFlag) IsBiasDisable() bool {
|
||||
return f&HandleRequestBiasDisable != 0
|
||||
}
|
||||
|
||||
// IsPullDown returns true if the line is requested with pull-down enabled.
|
||||
func (f HandleFlag) IsPullDown() bool {
|
||||
return f&HandleRequestPullDown != 0
|
||||
}
|
||||
|
||||
// IsPullUp returns true if the line is requested with pull-up enabled.
|
||||
func (f HandleFlag) IsPullUp() bool {
|
||||
return f&HandleRequestPullUp != 0
|
||||
}
|
||||
|
||||
// HandleData contains the logical value for each line.
|
||||
// Zero is a logical low and any other value is a logical high.
|
||||
type HandleData [HandlesMax]uint8
|
||||
|
||||
// EventRequest is a request for control of a line with event reporting enabled.
|
||||
type EventRequest struct {
|
||||
// The line to be requested.
|
||||
Offset uint32
|
||||
|
||||
// The line flags applied to this line.
|
||||
HandleFlags HandleFlag
|
||||
|
||||
// The type of events to report.
|
||||
EventFlags EventFlag
|
||||
|
||||
// The string identifying the requester to be applied to the line.
|
||||
Consumer [nameSize]byte
|
||||
|
||||
// The file handle for the requested line.
|
||||
// Set if the request is successful.
|
||||
Fd int32
|
||||
}
|
||||
|
||||
// EventFlag indicates the types of events that will be reported.
|
||||
type EventFlag uint32
|
||||
|
||||
const (
|
||||
// EventRequestRisingEdge requests rising edge events.
|
||||
// This means a transition from a low logical state to a high logical state.
|
||||
// For active high lines (the default) this means a transition from a
|
||||
// physical low to a physical high.
|
||||
// Note that for active low lines this means a transition from a physical
|
||||
// high to a physical low.
|
||||
EventRequestRisingEdge EventFlag = 1 << iota
|
||||
|
||||
// EventRequestFallingEdge requests falling edge events.
|
||||
// This means a transition from a high logical state to a low logical state.
|
||||
// For active high lines (the default) this means a transition from a
|
||||
// physical high to a physical low.
|
||||
// Note that for active low lines this means a transition from a physical
|
||||
// low to a physical high.
|
||||
EventRequestFallingEdge
|
||||
|
||||
// EventRequestBothEdges requests both rising and falling edge events.
|
||||
// This is equivalent to requesting both EventRequestRisingEdge and
|
||||
// EventRequestRisingEdge.
|
||||
EventRequestBothEdges = EventRequestRisingEdge | EventRequestFallingEdge
|
||||
)
|
||||
|
||||
// IsRisingEdge returns true if rising edge events have been requested.
|
||||
func (f EventFlag) IsRisingEdge() bool {
|
||||
return f&EventRequestRisingEdge != 0
|
||||
}
|
||||
|
||||
// IsFallingEdge returns true if falling edge events have been requested.
|
||||
func (f EventFlag) IsFallingEdge() bool {
|
||||
return f&EventRequestFallingEdge != 0
|
||||
}
|
||||
|
||||
// IsBothEdges returns true if both rising and falling edge events have been
|
||||
// requested.
|
||||
func (f EventFlag) IsBothEdges() bool {
|
||||
return f&EventRequestBothEdges == EventRequestBothEdges
|
||||
}
|
||||
|
||||
// EventData contains the details of a particular line event.
|
||||
//
|
||||
// This is returned via the event request fd in response to events.
|
||||
type EventData struct {
|
||||
// The time the event was detected.
|
||||
Timestamp uint64
|
||||
|
||||
// The type of event detected.
|
||||
ID uint32
|
||||
|
||||
// pad to workaround 64bit OS padding
|
||||
_ uint32
|
||||
}
|
||||
|
120
vendor/github.com/warthog618/gpiod/watcher.go
generated
vendored
Normal file
120
vendor/github.com/warthog618/gpiod/watcher.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright © 2019 Kent Gibson <warthog618@gmail.com>.
|
||||
|
||||
package gpiod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/warthog618/gpiod/uapi"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type watcher struct {
|
||||
epfd int
|
||||
|
||||
// fd to offset mapping
|
||||
evtfds map[int]int
|
||||
|
||||
// the handler for detected events
|
||||
eh EventHandler
|
||||
|
||||
// pipe to signal watcher to shutdown
|
||||
donefds []int
|
||||
|
||||
// closed once watcher exits
|
||||
doneCh chan struct{}
|
||||
}
|
||||
|
||||
func newWatcher(fds map[int]int, eh EventHandler) (w *watcher, err error) {
|
||||
var epfd int
|
||||
epfd, err = unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
unix.Close(epfd)
|
||||
}
|
||||
}()
|
||||
p := []int{0, 0}
|
||||
err = unix.Pipe2(p, unix.O_CLOEXEC)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
unix.Close(p[0])
|
||||
unix.Close(p[1])
|
||||
}
|
||||
}()
|
||||
epv := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(p[0])}
|
||||
err = unix.EpollCtl(epfd, unix.EPOLL_CTL_ADD, int(p[0]), &epv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for fd := range fds {
|
||||
epv.Fd = int32(fd)
|
||||
err = unix.EpollCtl(epfd, unix.EPOLL_CTL_ADD, fd, &epv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
w = &watcher{
|
||||
epfd: epfd,
|
||||
evtfds: fds,
|
||||
eh: eh,
|
||||
donefds: p,
|
||||
doneCh: make(chan struct{}),
|
||||
}
|
||||
go w.watch()
|
||||
return
|
||||
}
|
||||
|
||||
func (w *watcher) close() {
|
||||
unix.Write(w.donefds[1], []byte("bye"))
|
||||
<-w.doneCh
|
||||
for fd := range w.evtfds {
|
||||
unix.Close(fd)
|
||||
}
|
||||
unix.Close(w.donefds[0])
|
||||
unix.Close(w.donefds[1])
|
||||
}
|
||||
|
||||
func (w *watcher) watch() {
|
||||
epollEvents := make([]unix.EpollEvent, len(w.evtfds))
|
||||
defer close(w.doneCh)
|
||||
for {
|
||||
n, err := unix.EpollWait(w.epfd, epollEvents[:], -1)
|
||||
if err != nil {
|
||||
if err == unix.EBADF || err == unix.EINVAL {
|
||||
// fd closed so exit
|
||||
return
|
||||
}
|
||||
if err == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
panic(fmt.Sprintf("EpollWait unexpected error: %v", err))
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ev := epollEvents[i]
|
||||
fd := ev.Fd
|
||||
if fd == int32(w.donefds[0]) {
|
||||
unix.Close(w.epfd)
|
||||
return
|
||||
}
|
||||
evt, err := uapi.ReadEvent(uintptr(fd))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
le := LineEvent{
|
||||
Offset: w.evtfds[int(fd)],
|
||||
Timestamp: time.Duration(evt.Timestamp),
|
||||
Type: LineEventType(evt.ID),
|
||||
}
|
||||
w.eh(le)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue