A quick and dirty implementation

This commit is contained in:
Tony Blyler 2020-12-03 23:08:46 -05:00
parent 3682810e27
commit f6e9c70eb3
352 changed files with 242881 additions and 0 deletions

1
vendor/github.com/warthog618/gpiod/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
*.test

21
vendor/github.com/warthog618/gpiod/.travis.yml generated vendored Normal file
View 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
View 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
View 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
View file

@ -0,0 +1,439 @@
# gpiod
[![Build Status](https://travis-ci.org/warthog618/gpiod.svg)](https://travis-ci.org/warthog618/gpiod)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/warthog618/gpiod)
[![Go Report Card](https://goreportcard.com/badge/github.com/warthog618/gpiod)](https://goreportcard.com/report/github.com/warthog618/gpiod)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,75 @@
# uapi
[![GoDoc](https://godoc.org/github.com/warthog618/gpiod?status.svg)](https://godoc.org/github.com/warthog618/gpiod/uapi)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
View 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.")
}
}

View 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
View 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))
}

View 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
)

View 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
View 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
View 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)
}
}
}