build: upgrade to go 1.17 and dependencies

This commit is contained in:
2021-09-01 21:34:31 +02:00
parent bb6726a4b2
commit 36482fc9b8
749 changed files with 110609 additions and 117714 deletions

513
vendor/periph.io/x/conn/v3/.gohci.yml generated vendored Normal file
View File

@ -0,0 +1,513 @@
# Copyright 2021 The Periph Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
# See https://github.com/periph/gohci
version: 1
workers:
# BeagleBone Green Wireles by SeedStudio.
# https://beagleboard.org/green-wireless
- name: beaglebone-1860
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- ./...
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
- cmd:
- periph-smoketest
- gpio
- -pin1
- P8_45
- -pin2
- P8_46
# ODROID-C1+ by HardKernel
# https://www.hardkernel.com/shop/odroid-c1/
- name: odroid-483d
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- ./...
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./gpio-list
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- gpio-list
- -f
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
- cmd:
- periph-smoketest
- odroid-c1
- cmd:
- periph-smoketest
- i2c-testboard
- cmd:
- periph-smoketest
- onewire-testboard
- cmd:
- periph-smoketest
- spi-testboard
- cmd:
- periph-smoketest
- sysfs-benchmark
- -p
- 97
- -short
# Raspberry Pi 3
- name: raspberrypi-2f34
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- ./...
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./gpio-list
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- gpio-list
- -f
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
- cmd:
- periph-smoketest
- i2c-testboard
- cmd:
- periph-smoketest
- onewire-testboard
- -i2cbus
- 1
- cmd:
- periph-smoketest
- spi-testboard
- cmd:
- periph-smoketest
- sysfs-benchmark
- -p
- 12
- -short
- cmd:
- periph-smoketest
- bcm283x-benchmark
- -p
- 12
- -short
- cmd:
- periph-smoketest
- gpio
- -pin1
- P1_15
- -pin2
- P1_16
- cmd:
- periph-smoketest
- bcm283x
- -quick
# Old MacBook Pro on 10.9.
- name: mbp
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- ./...
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./gpio-list
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- gpio-list
- -f
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
# Laptop on Windows 10.
- name: win10
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- ./...
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./gpio-list
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- gpio-list
- -f
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list

15
vendor/periph.io/x/conn/v3/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,15 @@
# This is the list of The Periph Authors for copyright purposes.
#
# This does not necessarily list everyone who has contributed code, since in
# some cases, their employer may be the copyright holder. To see the full list
# of contributors, see the revision history in source control.
Cássio Botaro <cassiobotaro@gmail.com>
Fractal Industries, Inc
Google Inc.
Josh Gardiner
Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se>
Rifiniti, Inc
Stephan Sperber
Thorsten von Eicken <tve@voneicken.com>

4
vendor/periph.io/x/conn/v3/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
# Contributing
Thanks for contributing to the project! Please look at [the periph contribution
guidelines](https://periph.io/project/contributing/) first.

41
vendor/periph.io/x/conn/v3/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,41 @@
# This is the official list of people who can contribute
# (and typically have contributed) code to the periph repository.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# Names should be added to this file only after verifying that
# the individual or the individual's organization has agreed to
# the appropriate Contributor License Agreement, found here:
#
# https://cla.developers.google.com/
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file, depending on whether the
# individual or corporate CLA was used.
# Names should be added to this file like so:
# Individual's name <submission email address>
# Individual's name <submission email address> <email2> <emailN>
#
# An entry with multiple email addresses specifies that the
# first address should be used in the submit logs and
# that the other addresses should be recognized as the
# same person when interacting with Gerrit.
# Please keep the list sorted.
Cássio Botaro <cassiobotaro@gmail.com>
Eugene Dzhurynsky <jdevelop@gmail.com>
Hidetoshi Shimokawa <smkwhdts@gmail.com>
John Maguire <john.maguire@gmail.com>
Josh Gardiner <josh@zool.com>
Marc-Antoine Ruel <maruel@chromium.org> <maruel@gmail.com>
Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se>
Matias Insaurralde <matias@insaurral.de>
Seán C McCord <ulexus@gmail.com> <scm@cycoresys.com>
Stephan Sperber <sperberstephan@googlemail.com>
Thorsten von Eicken <tve@voneicken.com>

202
vendor/periph.io/x/conn/v3/LICENSE generated vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

57
vendor/periph.io/x/conn/v3/README.md generated vendored Normal file
View File

@ -0,0 +1,57 @@
# periph - Peripherals I/O in Go
Documentation is at https://periph.io
Join us for a chat on
[gophers.slack.com/messages/periph](https://gophers.slack.com/messages/periph),
get an [invite here](https://invite.slack.golangbridge.org/).
[![mascot](https://raw.githubusercontent.com/periph/website/master/site/static/img/periph-mascot-280.png)](https://periph.io/)
[![PkgGoDev](https://pkg.go.dev/badge/periph.io/x/conn/v3)](https://pkg.go.dev/periph.io/x/conn/v3)
[![Coverage
Status](https://codecov.io/gh/periph/conn/graph/badge.svg)](https://codecov.io/gh/periph/conn)
## Example
Blink a LED:
~~~go
package main
import (
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/host"
"periph.io/x/host/rpi"
)
func main() {
host.Init()
t := time.NewTicker(500 * time.Millisecond)
for l := gpio.Low; ; l = !l {
rpi.P1_33.Out(l)
<-t.C
}
}
~~~
Curious? Look at [supported devices](https://periph.io/device/) for more
examples!
## Authors
`periph` was initiated with and passion by [Marc-Antoine
Ruel](https://github.com/maruel). The full list of contributors is in
[AUTHORS](https://github.com/periph/conn/blob/main/AUTHORS) and
[CONTRIBUTORS](https://github.com/periph/conn/blob/main/CONTRIBUTORS).
## Disclaimer
This is not an official Google product (experimental or otherwise), it
is just code that happens to be owned by Google.
This project is not affiliated with the Go project.

20
vendor/periph.io/x/conn/v3/codecov.yml generated vendored Normal file
View File

@ -0,0 +1,20 @@
# Copyright 2020 The Periph Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
# https://docs.codecov.io/docs/codecovyml-reference
# and
# https://docs.codecov.io/docs/coverage-configuration
coverage:
precision: 1
range: "40...80"
round: nearest
status:
patch:
default:
target: 60%
threshold: 10%
project:
default:
target: 60%
threshold: 10%

103
vendor/periph.io/x/conn/v3/conn.go generated vendored Normal file
View File

@ -0,0 +1,103 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package conn
import "strconv"
// Resource is a basic resource (like a gpio pin) or a device.
type Resource interface {
// String returns a human readable identifier representing this resource in a
// descriptive way for the user. It is the same signature as fmt.Stringer.
String() string
// Halt stops the resource.
//
// Unlike a Conn, a Resource may not be closable, On the other hand, a
// resource can be halted. What halting entails depends on the resource
// device but it should stop motion, sensing loop, light emission or PWM
// output and go back into an inert state.
Halt() error
}
// Duplex declares whether communication can happen simultaneously both ways.
//
// Some protocol can be either depending on configuration settings, like UART.
type Duplex int
const (
// DuplexUnknown is used when the duplex of a connection is yet to be known.
//
// Some protocol can be configured either as half-duplex or full-duplex and
// the connection is not yet is a determinate state.
DuplexUnknown Duplex = 0
// Half means that communication can only occurs one way at a time.
//
// Examples include 1-wire and I²C.
Half Duplex = 1
// Full means that communication occurs simultaneously both ways in a
// synchronized manner.
//
// Examples include SPI (except 3-wire variant).
Full Duplex = 2
)
const duplexName = "DuplexUnknownHalfFull"
var duplexIndex = [...]uint8{0, 13, 17, 21}
func (i Duplex) String() string {
if i < 0 || i >= Duplex(len(duplexIndex)-1) {
return "Duplex(" + strconv.Itoa(int(i)) + ")"
}
return duplexName[duplexIndex[i]:duplexIndex[i+1]]
}
// Conn defines the interface for a connection on a point-to-point
// communication channel.
//
// The connection can either be unidirectional (read-only, write-only) or
// bidirectional (read-write). It can either be half-duplex or full duplex.
//
// This is the lowest common denominator for all point-to-point communication
// channels.
//
// Implementation are expected but not required to also implement the following
// interfaces:
//
// - fmt.Stringer which returns something meaningful to the user like "SPI0.1",
// "I2C1.76", "COM6", etc.
//
// - io.Reader and io.Writer as a way to use io.Copy() for half duplex
// operation.
//
// - io.Closer for the owner of the communication channel.
type Conn interface {
String() string
// Tx does a single transaction.
//
// For full duplex protocols (generally SPI, UART), the two buffers must have
// the same length as both reading and writing happen simultaneously.
//
// For half duplex protocols (I²C), there is no restriction as reading
// happens after writing, and r can be nil.
//
// Query Limits.MaxTxSize() to know if there is a limit on the buffer size
// per Tx() call.
Tx(w, r []byte) error
// Duplex returns the current duplex setting for this point-to-point
// connection.
//
// It is expected to be either Half or Full unless the connection itself is
// in an unknown state.
Duplex() Duplex
}
// Limits returns information about the connection's limits.
type Limits interface {
// MaxTxSize returns the maximum allowed data size to be sent as a single
// I/O.
//
// Returns 0 if undefined.
MaxTxSize() int
}

63
vendor/periph.io/x/conn/v3/doc.go generated vendored Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package conn defines core interfaces for protocols and connections.
//
// This package and its subpackages describe the base interfaces to connect the
// software with the real world. It doesn't contain any implementation but
// includes registries to enable the application to discover the available
// hardware.
//
// Concepts
//
// periph uses 3 layered concepts for interfacing:
//
// Bus → Port → Conn
//
// Not every subpackage expose all 3 concepts. In fact, most packages don't.
// For example, SPI doesn't expose Bus as the OSes generally only expose the
// Port, that is, a Chip Select (CS) line must be selected right upfront to get
// an handle. For I²C, there's no Port to configure, so selecting a "slave"
// address is sufficient to jump directly from a Bus to a Conn.
//
// periph doesn't have yet a concept of star-like communication network, like
// an IP network.
//
// Bus
//
// A Bus is a multi-point communication channel where one "master" and multiple
// "slaves" communicate together. In the case of periph, the Bus handle is
// assumed to be the "master". The "master" generally initiates communications
// and selects the "slave" to talk to.
//
// As the "master" selects a "slave" over a bus, a virtual Port is
// automatically created.
//
// Examples include SPI, I²C and 1-wire. In each case, selecting a
// communication line (Chip Select (CS) line for SPI, address for I²C or
// 1-wire) converts the Bus into a Port.
//
// Port
//
// A port is a point-to-point communication channel that is yet to be
// initialized. It cannot be used for communication until it is connected and
// transformed into a Conn. Configuring a Port converts it into a Conn. Not all
// Port need configuration.
//
// Conn
//
// A Conn is a fully configured half or full duplex communication channel that
// is point-to-point, only between two devices. It is ready to use like any
// readable and/or writable pipe.
//
// Subpackages
//
// Most connection-type specific subpackages include subpackages:
//
// → XXXreg: registry as that is populated by the host drivers and that can be
// leveraged by applications.
//
// → XXXtest: fake implementation that can be leveraged when writing device
// driver unit test.
package conn

45
vendor/periph.io/x/conn/v3/driver/driver.go generated vendored Normal file
View File

@ -0,0 +1,45 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package driver devices a host peripheral driver to register when
// initializing.
//
// Drivers that can be automatically discovered should be registered in
// driverreg so discovery is done automatically.
package driver
// Impl is a host peripheral driver implementation.
type Impl interface {
// String returns the name of the driver, as to be presented to the user.
//
// It must be unique in the list of registered drivers.
String() string
// Prerequisites returns a list of drivers that must be successfully loaded
// first before attempting to load this driver.
//
// A driver listing a prerequisite not registered is a fatal failure at
// initialization time.
Prerequisites() []string
// After returns a list of drivers that must be loaded first before
// attempting to load this driver.
//
// Unlike Prerequisites(), this driver will still be attempted even if the
// listed driver is missing or failed to load.
//
// This permits serialization without hard requirement.
After() []string
// Init initializes the driver.
//
// A driver may enter one of the three following state: loaded successfully,
// was skipped as irrelevant on this host, failed to load.
//
// On success, it must return true, nil.
//
// When irrelevant (skipped), it must return false, errors.New(<reason>).
//
// On failure, it must return true, errors.New(<reason>). The failure must
// state why it failed, for example an expected OS provided driver couldn't
// be opened, e.g. /dev/gpiomem on Raspbian.
Init() (bool, error)
}

View File

@ -0,0 +1,215 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package driverreg is a registry for all host driver implementation that can
// be automatically discovered.
package driverreg
import (
"errors"
"strconv"
"strings"
"sync"
"periph.io/x/conn/v3/driver"
)
// DriverFailure is a driver that wasn't loaded, either because it was skipped
// or because it failed to load.
type DriverFailure struct {
D driver.Impl
Err error
}
func (d DriverFailure) String() string {
out := d.D.String() + ": "
if d.Err != nil {
out += d.Err.Error()
} else {
out += "<nil>"
}
return out
}
// State is the state of loaded device drivers.
//
// Each list is sorted by the driver name.
type State struct {
Loaded []driver.Impl
Skipped []DriverFailure
Failed []DriverFailure
}
// Init initialises all the relevant drivers.
//
// Drivers are started concurrently.
//
// It is safe to call this function multiple times, the previous state is
// returned on later calls.
//
// Users will want to use host.Init(), which guarantees a baseline of included
// host drivers.
func Init() (*State, error) {
mu.Lock()
defer mu.Unlock()
if state != nil {
return state, nil
}
return initImpl()
}
// Register registers a driver to be initialized automatically on Init().
//
// The d.String() value must be unique across all registered drivers.
//
// It is an error to call Register() after Init() was called.
func Register(d driver.Impl) error {
mu.Lock()
defer mu.Unlock()
if state != nil {
return errors.New("periph: can't call Register() after Init()")
}
n := d.String()
if _, ok := byName[n]; ok {
return errors.New("periph: driver with same name " + strconv.Quote(n) + " was already registered")
}
byName[n] = d
return nil
}
// MustRegister calls Register() and panics if registration fails.
//
// This is the function to call in a driver's package init() function.
func MustRegister(d driver.Impl) {
if err := Register(d); err != nil {
panic(err)
}
}
//
var (
// mu guards byName and state.
// - byName is only mutated by Register().
// - state is only mutated by Init().
//
// Once Init() is called, Register() refuses registering more drivers, thus
// byName is immutable once Init() started.
mu sync.Mutex
byName = map[string]driver.Impl{}
state *State
)
// stage is a set of drivers that can be loaded in parallel.
type stage struct {
// Subset of byName drivers, for the ones in this stage.
drvs map[string]driver.Impl
}
// explodeStages creates one or multiple stages by processing byName.
//
// It searches if there's any driver than has dependency on another driver and
// create stages from this DAG.
//
// It also verifies that there is not cycle in the DAG.
//
// When this function starts, allDriver and byName are guaranteed to be
// immutable. state must not be touched by this function.
func explodeStages() ([]*stage, error) {
// First, create the DAG.
dag := map[string]map[string]struct{}{}
for name, d := range byName {
m := map[string]struct{}{}
for _, p := range d.Prerequisites() {
if _, ok := byName[p]; !ok {
return nil, errors.New("periph: unsatisfied dependency " + strconv.Quote(name) + "->" + strconv.Quote(p) + "; it is missing; skipping")
}
m[p] = struct{}{}
}
for _, p := range d.After() {
// Skip undefined drivers silently, unlike Prerequisites().
if _, ok := byName[p]; ok {
m[p] = struct{}{}
}
}
dag[name] = m
}
// Create stages.
var stages []*stage
for len(dag) != 0 {
s := &stage{drvs: map[string]driver.Impl{}}
for name, deps := range dag {
// This driver has no dependency, add it to the current stage.
if len(deps) == 0 {
s.drvs[name] = byName[name]
delete(dag, name)
}
}
if len(s.drvs) == 0 {
// Print out the remaining DAG so users can diagnose.
// It'd probably be nicer if it were done in Register()?
s := make([]string, 0, len(dag))
for name, deps := range dag {
x := make([]string, 0, len(deps))
for d := range deps {
x = insertString(x, d)
}
s = insertString(s, name+": "+strings.Join(x, ", "))
}
return nil, errors.New("periph: found cycle(s) in drivers dependencies:\n" + strings.Join(s, "\n"))
}
stages = append(stages, s)
// Trim the dependencies for the items remaining in the dag.
for passed := range s.drvs {
for name := range dag {
delete(dag[name], passed)
}
}
}
return stages, nil
}
func insertDriver(l []driver.Impl, d driver.Impl) []driver.Impl {
n := d.String()
i := search(len(l), func(i int) bool { return l[i].String() > n })
l = append(l, nil)
copy(l[i+1:], l[i:])
l[i] = d
return l
}
func insertDriverFailure(l []DriverFailure, f DriverFailure) []DriverFailure {
n := f.String()
i := search(len(l), func(i int) bool { return l[i].String() > n })
l = append(l, DriverFailure{})
copy(l[i+1:], l[i:])
l[i] = f
return l
}
func insertString(l []string, s string) []string {
i := search(len(l), func(i int) bool { return l[i] > s })
l = append(l, "")
copy(l[i+1:], l[i:])
l[i] = s
return l
}
// search implements the same algorithm as sort.Search().
//
// It was extracted to to not depend on sort, which depends on reflect.
func search(n int, f func(int) bool) int {
lo := 0
for hi := n; lo < hi; {
if i := int(uint(lo+hi) >> 1); !f(i) {
lo = i + 1
} else {
hi = i
}
}
return lo
}

View File

@ -0,0 +1,103 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// This file contains the parallelized driver loading logic. It is meant to be
// load the drivers as fast as possible by parallelising work.
// +build !tinygo
package driverreg
import (
"errors"
"strconv"
"sync"
"periph.io/x/conn/v3/driver"
)
func initImpl() (*State, error) {
state = &State{}
// At this point, byName is guaranteed to be immutable.
cD := make(chan driver.Impl)
cS := make(chan DriverFailure)
cE := make(chan DriverFailure)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for d := range cD {
state.Loaded = insertDriver(state.Loaded, d)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for f := range cS {
state.Skipped = insertDriverFailure(state.Skipped, f)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for f := range cE {
state.Failed = insertDriverFailure(state.Failed, f)
}
}()
stages, err := explodeStages()
if err != nil {
return state, err
}
loaded := make(map[string]struct{}, len(byName))
for _, s := range stages {
s.loadParallel(loaded, cD, cS, cE)
}
close(cD)
close(cS)
close(cE)
wg.Wait()
return state, nil
}
// loadParallel loads all the drivers for this stage in parallel.
//
// Updates loaded in a safe way.
func (s *stage) loadParallel(loaded map[string]struct{}, cD chan<- driver.Impl, cS, cE chan<- DriverFailure) {
success := make(chan string)
go func() {
defer close(success)
wg := sync.WaitGroup{}
loop:
for name, drv := range s.drvs {
// Intentionally do not look at After(), only Prerequisites().
for _, dep := range drv.Prerequisites() {
if _, ok := loaded[dep]; !ok {
cS <- DriverFailure{drv, errors.New("dependency not loaded: " + strconv.Quote(dep))}
continue loop
}
}
// Not skipped driver, attempt loading in a goroutine.
wg.Add(1)
go func(n string, d driver.Impl) {
defer wg.Done()
if ok, err := d.Init(); ok {
if err == nil {
cD <- d
success <- n
return
}
cE <- DriverFailure{d, err}
} else {
cS <- DriverFailure{d, err}
}
}(name, drv)
}
wg.Wait()
}()
for s := range success {
loaded[s] = struct{}{}
}
}

View File

@ -0,0 +1,55 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// This file contains the single threaded driver loading code, to be used on
// low performance cores.
// +build tinygo
package driverreg
import (
"errors"
"strconv"
)
func initImpl() (*State, error) {
state = &State{}
// At this point, byName is guaranteed to be immutable.
stages, err := explodeStages()
if err != nil {
return state, err
}
loaded := make(map[string]struct{}, len(byName))
for _, s := range stages {
s.loadSerial(state, loaded)
}
return state, nil
}
// loadSerial loads all the drivers for this stage, one after the other.
func (s *stage) loadSerial(state *State, loaded map[string]struct{}) {
for name, drv := range s.drvs {
// Intentionally do not look at After(), only Prerequisites().
for _, dep := range drv.Prerequisites() {
if _, ok := loaded[dep]; !ok {
state.Skipped = insertDriverFailure(state.Skipped, DriverFailure{drv, errors.New("dependency not loaded: " + strconv.Quote(dep))})
goto loop
}
}
// Not skipped driver, attempt loading in a goroutine.
if ok, err := drv.Init(); ok {
if err == nil {
state.Loaded = insertDriver(state.Loaded, drv)
loaded[name] = struct{}{}
} else {
state.Failed = insertDriverFailure(state.Failed, DriverFailure{drv, err})
}
} else {
state.Skipped = insertDriverFailure(state.Skipped, DriverFailure{drv, err})
}
loop:
}
}

26
vendor/periph.io/x/conn/v3/gpio/func.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package gpio
import "periph.io/x/conn/v3/pin"
// Well known pin functionality.
const (
// Inputs
IN pin.Func = "IN" // Input
IN_HIGH pin.Func = "In/High" // Read high
IN_LOW pin.Func = "In/Low" // Read low
// Outputs
OUT pin.Func = "OUT" // Output, drive
OUT_OC pin.Func = "OUT_OPEN" // Output, open collector/drain
OUT_HIGH pin.Func = "Out/High" // Drive high
OUT_LOW pin.Func = "Out/Low" // Drive low; open collector low
FLOAT pin.Func = "FLOAT" // Input float or Output open collector high
CLK pin.Func = "CLK" // Clock is a subset of a PWM, with a 50% duty cycle
PWM pin.Func = "PWM" // Pulse Width Modulation, which is a clock with variable duty cycle
)

329
vendor/periph.io/x/conn/v3/gpio/gpio.go generated vendored Normal file
View File

@ -0,0 +1,329 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package gpio defines digital pins.
//
// All GPIO implementations are expected to implement PinIO but the device
// driver may accept a more specific one like PinIn or PinOut.
package gpio
import (
"errors"
"strconv"
"strings"
"time"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/pin"
)
// Interfaces
// Level is the level of the pin: Low or High.
type Level bool
const (
// Low represents 0v.
Low Level = false
// High represents Vin, generally 3.3v or 5v.
High Level = true
)
func (l Level) String() string {
if l == Low {
return "Low"
}
return "High"
}
// Pull specifies the internal pull-up or pull-down for a pin set as input.
type Pull uint8
// Acceptable pull values.
const (
PullNoChange Pull = 0 // Do not change the previous pull resistor setting or an unknown value
Float Pull = 1 // Let the input float
PullDown Pull = 2 // Apply pull-down
PullUp Pull = 3 // Apply pull-up
)
const pullName = "PullNoChangeFloatPullDownPullUp"
var pullIndex = [...]uint8{0, 12, 17, 25, 31}
func (i Pull) String() string {
if i >= Pull(len(pullIndex)-1) {
return "Pull(" + strconv.Itoa(int(i)) + ")"
}
return pullName[pullIndex[i]:pullIndex[i+1]]
}
// Edge specifies if an input pin should have edge detection enabled.
//
// Only enable it when needed, since this causes system interrupts.
type Edge int
// Acceptable edge detection values.
const (
NoEdge Edge = 0
RisingEdge Edge = 1
FallingEdge Edge = 2
BothEdges Edge = 3
)
const edgeName = "NoEdgeRisingEdgeFallingEdgeBothEdges"
var edgeIndex = [...]uint8{0, 6, 16, 27, 36}
func (i Edge) String() string {
if i >= Edge(len(edgeIndex)-1) {
return "Edge(" + strconv.Itoa(int(i)) + ")"
}
return edgeName[edgeIndex[i]:edgeIndex[i+1]]
}
const (
// DutyMax is a duty cycle of 100%.
DutyMax Duty = 1 << 24
// DutyHalf is a 50% duty PWM, which boils down to a normal clock.
DutyHalf Duty = DutyMax / 2
)
// Duty is the duty cycle for a PWM.
//
// Valid values are between 0 and DutyMax.
type Duty int32
func (d Duty) String() string {
// TODO(maruel): Implement one fractional number.
return strconv.Itoa(int((d+50)/(DutyMax/100))) + "%"
}
// Valid returns true if the Duty cycle value is valid.
func (d Duty) Valid() bool {
return d >= 0 && d <= DutyMax
}
// ParseDuty parses a string and converts it to a Duty value.
func ParseDuty(s string) (Duty, error) {
percent := strings.HasSuffix(s, "%")
if percent {
s = s[:len(s)-1]
}
i64, err := strconv.ParseInt(s, 10, 32)
if err != nil {
return 0, err
}
i := Duty(i64)
if percent {
// TODO(maruel): Add support for fractional number.
if i < 0 {
return 0, errors.New("duty must be >= 0%")
}
if i > 100 {
return 0, errors.New("duty must be <= 100%")
}
return ((i * DutyMax) + 49) / 100, nil
}
if i < 0 {
return 0, errors.New("duty must be >= 0")
}
if i > DutyMax {
return 0, errors.New("duty must be <= " + strconv.Itoa(int(DutyMax)))
}
return i, nil
}
// PinIn is an input GPIO pin.
//
// It may optionally support internal pull resistor and edge based triggering.
//
// A button is semantically a PinIn. So if you are looking to read from a
// button, PinIn is the interface you are looking for.
type PinIn interface {
pin.Pin
// In setups a pin as an input.
//
// If WaitForEdge() is planned to be called, make sure to use one of the Edge
// value. Otherwise, use NoEdge to not generated unneeded hardware interrupts.
//
// Calling In() will try to empty the accumulated edges but it cannot be 100%
// reliable due to the OS (linux) and its driver. It is possible that on a
// gpio that is as input, doing a quick Out(), In() may return an edge that
// occurred before the Out() call.
In(pull Pull, edge Edge) error
// Read return the current pin level.
//
// Behavior is undefined if In() wasn't used before.
//
// In some rare case, it is possible that Read() fails silently. This happens
// if another process on the host messes up with the pin after In() was
// called. In this case, call In() again.
Read() Level
// WaitForEdge() waits for the next edge or immediately return if an edge
// occurred since the last call.
//
// Only waits for the kind of edge as specified in a previous In() call.
// Behavior is undefined if In() with a value other than NoEdge wasn't called
// before.
//
// Returns true if an edge was detected during or before this call. Return
// false if the timeout occurred or In() was called while waiting, causing the
// function to exit.
//
// Multiple edges may or may not accumulate between two calls to
// WaitForEdge(). The behavior in this case is undefined and is OS driver
// specific.
//
// It is not required to call Read() to reset the edge detection.
//
// Specify -1 to effectively disable timeout.
WaitForEdge(timeout time.Duration) bool
// Pull returns the internal pull resistor if the pin is set as input pin.
//
// Returns PullNoChange if the value cannot be read.
Pull() Pull
// DefaultPull returns the pull that is initialized on CPU/device reset. This
// is useful to determine if the pin is acceptable for operation with
// certain devices.
DefaultPull() Pull
}
// PinOut is an output GPIO pin.
//
// A LED, a buzzer, a servo, are semantically a PinOut. So if you are looking
// to control these, PinOut is the interface you are looking for.
type PinOut interface {
pin.Pin
// Out sets a pin as output if it wasn't already and sets the initial value.
//
// After the initial call to ensure that the pin has been set as output, it
// is generally safe to ignore the error returned.
//
// Out() tries to empty the accumulated edges detected if the gpio was
// previously set as input but this is not 100% guaranteed due to the OS.
Out(l Level) error
// PWM sets the PWM output on supported pins, if the pin has hardware PWM
// support.
//
// To use as a general purpose clock, set duty to DutyHalf. Some pins may
// only support DutyHalf and no other value.
//
// Using 0 as frequency will use the optimal value as supported/preferred by
// the pin.
//
// To use as a servo, see https://en.wikipedia.org/wiki/Servo_control as an
// explanation how to calculate duty.
PWM(duty Duty, f physic.Frequency) error
}
// PinIO is a GPIO pin that supports both input and output. It matches both
// interfaces PinIn and PinOut.
//
// A GPIO pin implementing PinIO may fail at either input or output or both.
type PinIO interface {
pin.Pin
// PinIn
In(pull Pull, edge Edge) error
Read() Level
WaitForEdge(timeout time.Duration) bool
Pull() Pull
DefaultPull() Pull
// PinOut
Out(l Level) error
PWM(duty Duty, f physic.Frequency) error
}
// INVALID implements PinIO and fails on all access.
var INVALID PinIO
// RealPin is implemented by aliased pin and allows the retrieval of the real
// pin underlying an alias.
//
// Aliases are created by RegisterAlias. Aliases permits presenting a user
// friendly GPIO pin name while representing the underlying real pin.
//
// The purpose of the RealPin is to be able to cleanly test whether an arbitrary
// gpio.PinIO returned by ByName is an alias for another pin, and resolve it.
type RealPin interface {
Real() PinIO // Real returns the real pin behind an Alias
}
//
// errInvalidPin is returned when trying to use INVALID.
var errInvalidPin = errors.New("gpio: invalid pin")
func init() {
INVALID = invalidPin{}
}
// invalidPin implements PinIO for compatibility but fails on all access.
type invalidPin struct {
}
func (invalidPin) String() string {
return "INVALID"
}
func (invalidPin) Halt() error {
return nil
}
func (invalidPin) Number() int {
return -1
}
func (invalidPin) Name() string {
return "INVALID"
}
func (invalidPin) Function() string {
return ""
}
func (invalidPin) Func() pin.Func {
return pin.FuncNone
}
func (invalidPin) SupportedFuncs() []pin.Func {
return nil
}
func (invalidPin) SetFunc(f pin.Func) error {
return errInvalidPin
}
func (invalidPin) In(Pull, Edge) error {
return errInvalidPin
}
func (invalidPin) Read() Level {
return Low
}
func (invalidPin) WaitForEdge(timeout time.Duration) bool {
return false
}
func (invalidPin) Pull() Pull {
return PullNoChange
}
func (invalidPin) DefaultPull() Pull {
return PullNoChange
}
func (invalidPin) Out(Level) error {
return errInvalidPin
}
func (invalidPin) PWM(Duty, physic.Frequency) error {
return errInvalidPin
}
var _ PinIn = INVALID
var _ PinOut = INVALID
var _ PinIO = INVALID
var _ pin.PinFunc = &invalidPin{}

213
vendor/periph.io/x/conn/v3/gpio/gpioreg/gpioreg.go generated vendored Normal file
View File

@ -0,0 +1,213 @@
// Copyright 2017 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package gpioreg defines a registry for the known digital pins.
package gpioreg
import (
"errors"
"strconv"
"sync"
"periph.io/x/conn/v3/gpio"
)
// ByName returns a GPIO pin from its name, gpio number or one of its aliases.
//
// For example on a Raspberry Pi, the following values will return the same
// GPIO: the gpio as a number "2", the chipset name "GPIO2", the board pin
// position "P1_3", it's function name "I2C1_SDA".
//
// Returns nil if the gpio pin is not present.
func ByName(name string) gpio.PinIO {
mu.Lock()
defer mu.Unlock()
if p, ok := byName[name]; ok {
return p
}
if dest, ok := byAlias[name]; ok {
if p := getByNameDeep(dest); p != nil {
// Wraps the destination in an alias, so the name makes sense to the user.
// The main drawback is that casting into other gpio interfaces like
// gpio.PinPWM requires going through gpio.RealPin first.
return &pinAlias{p, name}
}
}
return nil
}
// All returns all the GPIO pins available on this host.
//
// The list is guaranteed to be in order of name using 'natural sorting'.
//
// This list excludes aliases.
//
// This list excludes non-GPIO pins like GROUND, V3_3, etc, since they are not
// GPIO.
func All() []gpio.PinIO {
mu.Lock()
defer mu.Unlock()
out := make([]gpio.PinIO, 0, len(byName))
for _, p := range byName {
out = insertPinByName(out, p)
}
return out
}
// Aliases returns all pin aliases.
//
// The list is guaranteed to be in order of aliase name.
func Aliases() []gpio.PinIO {
mu.Lock()
defer mu.Unlock()
out := make([]gpio.PinIO, 0, len(byAlias))
for name, dest := range byAlias {
// Skip aliases that were not resolved.
if p := getByNameDeep(dest); p != nil {
out = insertPinByName(out, &pinAlias{p, name})
}
}
return out
}
// Register registers a GPIO pin.
//
// Registering the same pin number or name twice is an error.
//
// The pin registered cannot implement the interface RealPin.
func Register(p gpio.PinIO) error {
name := p.Name()
if len(name) == 0 {
return errors.New("gpioreg: can't register a pin with no name")
}
if r, ok := p.(gpio.RealPin); ok {
return errors.New("gpioreg: can't register pin " + strconv.Quote(name) + ", it is already an alias to " + strconv.Quote(r.Real().String()))
}
mu.Lock()
defer mu.Unlock()
if orig, ok := byName[name]; ok {
return errors.New("gpioreg: can't register pin " + strconv.Quote(name) + " twice; already registered as " + strconv.Quote(orig.String()))
}
if dest, ok := byAlias[name]; ok {
return errors.New("gpioreg: can't register pin " + strconv.Quote(name) + "; an alias already exist to: " + strconv.Quote(dest))
}
byName[name] = p
return nil
}
// RegisterAlias registers an alias for a GPIO pin.
//
// It is possible to register an alias for a pin that itself has not been
// registered yet. It is valid to register an alias to another alias. It is
// valid to register the same alias multiple times, overriding the previous
// alias.
func RegisterAlias(alias string, dest string) error {
if len(alias) == 0 {
return errors.New("gpioreg: can't register an alias with no name")
}
if len(dest) == 0 {
return errors.New("gpioreg: can't register alias " + strconv.Quote(alias) + " with no dest")
}
mu.Lock()
defer mu.Unlock()
if _, ok := byName[alias]; ok {
return errors.New("gpioreg: can't register alias " + strconv.Quote(alias) + " for a pin that exists")
}
byAlias[alias] = dest
return nil
}
// Unregister removes a previously registered GPIO pin or alias from the GPIO
// pin registry.
//
// This can happen when a GPIO pin is exposed via an USB device and the device
// is unplugged, or when a generic OS provided pin is superseded by a CPU
// specific implementation.
func Unregister(name string) error {
mu.Lock()
defer mu.Unlock()
if _, ok := byName[name]; ok {
delete(byName, name)
return nil
}
if _, ok := byAlias[name]; ok {
delete(byAlias, name)
return nil
}
return errors.New("gpioreg: can't unregister unknown pin name " + strconv.Quote(name))
}
//
var (
mu sync.Mutex
byName = map[string]gpio.PinIO{}
byAlias = map[string]string{}
)
// pinAlias implements an alias for a PinIO.
//
// pinAlias implements the RealPin interface, which allows querying for the
// real pin under the alias.
type pinAlias struct {
gpio.PinIO
name string
}
// String returns the alias name along the real pin's Name() in parenthesis, if
// known, else the real pin's number.
func (a *pinAlias) String() string {
return a.name + "(" + a.PinIO.Name() + ")"
}
// Name returns the pinAlias's name.
func (a *pinAlias) Name() string {
return a.name
}
// Real returns the real pin behind the alias
func (a *pinAlias) Real() gpio.PinIO {
return a.PinIO
}
// getByNameDeep recursively resolves the aliases to get the pin.
func getByNameDeep(name string) gpio.PinIO {
if p, ok := byName[name]; ok {
return p
}
if dest, ok := byAlias[name]; ok {
if p := getByNameDeep(dest); p != nil {
// Return the deep pin directly, bypassing the aliases.
return p
}
}
return nil
}
// insertPinByName inserts pin p into list l while keeping l ordered by name.
func insertPinByName(l []gpio.PinIO, p gpio.PinIO) []gpio.PinIO {
n := p.Name()
i := search(len(l), func(i int) bool { return lessNatural(n, l[i].Name()) })
l = append(l, nil)
copy(l[i+1:], l[i:])
l[i] = p
return l
}
// search implements the same algorithm as sort.Search().
//
// It was extracted to to not depend on sort, which depends on reflect.
func search(n int, f func(int) bool) int {
lo := 0
for hi := n; lo < hi; {
if i := int(uint(lo+hi) >> 1); !f(i) {
lo = i + 1
} else {
hi = i
}
}
return lo
}

76
vendor/periph.io/x/conn/v3/gpio/gpioreg/natsort.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package gpioreg
import (
"strconv"
)
// lessNatural does a 'natural' comparison on the two strings.
//
// It is extracted from https://github.com/maruel/natural.
func lessNatural(a, b string) bool {
for {
if a == b {
return false
}
if p := commonPrefix(a, b); p != 0 {
a = a[p:]
b = b[p:]
}
if ia := digits(a); ia > 0 {
if ib := digits(b); ib > 0 {
// Both sides have digits.
an, aerr := strconv.ParseUint(a[:ia], 10, 64)
bn, berr := strconv.ParseUint(b[:ib], 10, 64)
if aerr == nil && berr == nil {
if an != bn {
return an < bn
}
// Semantically the same digits, e.g. "00" == "0", "01" == "1". In
// this case, only continue processing if there's trailing data on
// both sides, otherwise do lexical comparison.
if ia != len(a) && ib != len(b) {
a = a[ia:]
b = b[ib:]
continue
}
}
}
}
return a < b
}
}
// commonPrefix returns the common prefix except for digits.
func commonPrefix(a, b string) int {
m := len(a)
if n := len(b); n < m {
m = n
}
if m == 0 {
return 0
}
_ = a[m-1]
_ = b[m-1]
for i := 0; i < m; i++ {
ca := a[i]
cb := b[i]
if (ca >= '0' && ca <= '9') || (cb >= '0' && cb <= '9') || ca != cb {
return i
}
}
return m
}
func digits(s string) int {
for i := 0; i < len(s); i++ {
c := s[i]
if c < '0' || c > '9' {
return i
}
}
return len(s)
}

View File

@ -0,0 +1,220 @@
// Copyright 2017 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package gpiostream defines digital streams.
//
// Warning
//
// This package is still in flux as development is on-going.
package gpiostream
import (
"fmt"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/pin"
)
// Stream is the interface to define a generic stream.
type Stream interface {
// Frequency is the minimum data rate at which the binary stream is usable.
//
// For example, a bit stream may have a 10kHz data rate.
Frequency() physic.Frequency
// Duration of the binary stream. For infinitely looping streams, it is the
// duration of the non-looping part.
Duration() time.Duration
}
// BitStream is a stream of bits to be written or read.
type BitStream struct {
// Bits is a densely packed bitstream.
//
// The stream is required to be a multiple of 8 samples.
Bits []byte
// Freq is the rate at each the bit (not byte) stream should be processed.
Freq physic.Frequency
// LSBF when true means than Bits is in LSB-first. When false, the data is
// MSB-first.
//
// With MSBF, the first bit processed is the most significant one (0x80). For
// example, I²C, I2S PCM and SPI use MSB-first at the word level. This
// requires to pack words correctly.
//
// With LSBF, the first bit processed is the least significant one (0x01).
// For example, Ethernet uses LSB-first at the byte level and MSB-first at
// the word level.
LSBF bool
}
// Frequency implements Stream.
func (b *BitStream) Frequency() physic.Frequency {
return b.Freq
}
// Duration implements Stream.
func (b *BitStream) Duration() time.Duration {
if b.Freq == 0 {
return 0
}
return b.Freq.Period() * time.Duration(len(b.Bits)*8)
}
// GoString implements fmt.GoStringer.
func (b *BitStream) GoString() string {
return fmt.Sprintf("&gpiostream.BitStream{Bits: %x, Freq:%s, LSBF:%t}", b.Bits, b.Freq, b.LSBF)
}
// EdgeStream is a stream of edges to be written.
//
// This struct is more efficient than BitStream for short repetitive pulses,
// like controlling a servo. A PWM can be created by specifying a slice of
// twice the same resolution and make it looping via a Program.
type EdgeStream struct {
// Edges is the list of Level change. It is assumed that the signal starts
// with gpio.High. Use a duration of 0 for Edges[0] to start with a Low
// instead of the default High.
//
// The value is a multiple of Res. Use a 0 value to 'extend' a continuous
// signal that lasts more than "2^16-1*Res" duration by skipping a pulse.
Edges []uint16
// Res is the minimum resolution at which the edges should be
// rasterized.
//
// The lower the value, the more memory shall be used when rasterized.
Freq physic.Frequency
}
// Frequency implements Stream.
func (e *EdgeStream) Frequency() physic.Frequency {
return e.Freq
}
// Duration implements Stream.
func (e *EdgeStream) Duration() time.Duration {
if e.Freq == 0 {
return 0
}
t := 0
for _, edge := range e.Edges {
t += int(edge)
}
return e.Freq.Period() * time.Duration(t)
}
// Program is a loop of streams.
//
// This is itself a stream, it can be used to reduce memory usage when repeated
// patterns are used.
type Program struct {
Parts []Stream // Each part must be a BitStream, EdgeStream or Program
Loops int // Set to -1 to create an infinite loop
}
// Frequency implements Stream.
func (p *Program) Frequency() physic.Frequency {
if p.Loops == 0 {
return 0
}
var buf [16]physic.Frequency
freqs := buf[:0]
for _, part := range p.Parts {
if f := part.Frequency(); f != 0 {
freqs = insertFreq(freqs, f)
}
}
if len(freqs) == 0 {
return 0
}
f := freqs[0]
for i := 1; i < len(freqs); i++ {
if r := freqs[i]; r*2 < f {
break
}
// Take in account Nyquist rate. https://wikipedia.org/wiki/Nyquist_rate
f *= 2
}
return f
}
// Duration implements Stream.
func (p *Program) Duration() time.Duration {
if p.Loops == 0 {
return 0
}
var d time.Duration
for _, s := range p.Parts {
d += s.Duration()
}
if p.Loops > 1 {
d *= time.Duration(p.Loops)
}
return d
}
//
// PinIn allows to read a bit stream from a pin.
//
// Caveat
//
// This interface doesn't enable sampling multiple pins in a
// synchronized way or reading in a continuous uninterrupted way. As such, it
// should be considered experimental.
type PinIn interface {
pin.Pin
// StreamIn reads for the pin at the specified resolution to fill the
// provided buffer.
//
// May only support a subset of the structs implementing Stream.
StreamIn(p gpio.Pull, b Stream) error
}
// PinOut allows to stream to a pin.
//
// The Stream may be a Program, a BitStream or an EdgeStream. If it is a
// Program that is an infinite loop, a separate goroutine can be used to cancel
// the program. In this case StreamOut() returns without an error.
//
// Caveat
//
// This interface doesn't enable streaming to multiple pins in a
// synchronized way or reading in a continuous uninterrupted way. As such, it
// should be considered experimental.
type PinOut interface {
pin.Pin
StreamOut(s Stream) error
}
//
// insertFreq inserts in reverse order, highest frequency first.
func insertFreq(l []physic.Frequency, f physic.Frequency) []physic.Frequency {
i := search(len(l), func(i int) bool { return l[i] < f })
l = append(l, 0)
copy(l[i+1:], l[i:])
l[i] = f
return l
}
// search implements the same algorithm as sort.Search().
//
// It was extracted to to not depend on sort, which depends on reflect.
func search(n int, f func(int) bool) int {
lo := 0
for hi := n; lo < hi; {
if i := int(uint(lo+hi) >> 1); !f(i) {
lo = i + 1
} else {
hi = i
}
}
return lo
}
var _ Stream = &BitStream{}
var _ Stream = &EdgeStream{}
var _ Stream = &Program{}

13
vendor/periph.io/x/conn/v3/i2c/func.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package i2c
import "periph.io/x/conn/v3/pin"
// Well known pin functionality.
const (
SCL pin.Func = "I2C_SCL" // Clock
SDA pin.Func = "I2C_SDA" // Data
)

135
vendor/periph.io/x/conn/v3/i2c/i2c.go generated vendored Normal file
View File

@ -0,0 +1,135 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package i2c defines the API to communicate with devices over the I²C
// protocol.
//
// As described in https://periph.io/x/conn/v3#hdr-Concepts, periph.io uses
// the concepts of Bus, Port and Conn.
//
// In the package i2c, 'Port' is not exposed, since once you know the I²C
// device address, there's no unconfigured Port to configure.
//
// Instead, the package includes the adapter 'Dev' to directly convert an I²C
// bus 'i2c.Bus' into a connection 'conn.Conn' by only specifying the device
// I²C address.
//
// See https://en.wikipedia.org/wiki/I%C2%B2C for more information.
package i2c
import (
"errors"
"io"
"strconv"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
// Bus defines the interface a concrete I²C driver must implement.
//
// This interface is consummed by a device driver for a device sitting on a bus.
//
// This interface doesn't implement conn.Conn since a device address must be
// specified. Use i2cdev.Dev as an adapter to get a conn.Conn compatible
// object.
type Bus interface {
String() string
// Tx does a transaction at the specified device address.
//
// Write is done first, then read. One of 'w' or 'r' can be omitted for a
// unidirectional operation.
Tx(addr uint16, w, r []byte) error
// SetSpeed changes the bus speed, if supported.
//
// On linux due to the way the I²C sysfs driver is exposed in userland,
// calling this function will likely affect *all* I²C buses on the host.
SetSpeed(f physic.Frequency) error
}
// BusCloser is an I²C bus that can be closed.
//
// This interface is meant to be handled by the application and not the device
// driver. A device driver doesn't "own" a bus, hence it must operate on a Bus,
// not a BusCloser.
type BusCloser interface {
io.Closer
Bus
}
// Pins defines the pins that an I²C bus interconnect is using on the host.
//
// It is expected that a implementer of Bus also implement Pins but this is not
// a requirement.
type Pins interface {
// SCL returns the CLK (clock) pin.
SCL() gpio.PinIO
// SDA returns the DATA pin.
SDA() gpio.PinIO
}
// Dev is a device on a I²C bus.
//
// It implements conn.Conn.
//
// It saves from repeatedly specifying the device address.
type Dev struct {
Bus Bus
Addr uint16
}
func (d *Dev) String() string {
s := "<nil>"
if d.Bus != nil {
s = d.Bus.String()
}
return s + "(" + strconv.Itoa(int(d.Addr)) + ")"
}
// Tx does a transaction by adding the device's address to each command.
//
// It's a wrapper for Bus.Tx().
func (d *Dev) Tx(w, r []byte) error {
return d.Bus.Tx(d.Addr, w, r)
}
// Write writes to the I²C bus without reading, implementing io.Writer.
//
// It's a wrapper for Tx()
func (d *Dev) Write(b []byte) (int, error) {
if err := d.Tx(b, nil); err != nil {
return 0, err
}
return len(b), nil
}
// Duplex always return conn.Half for I²C.
func (d *Dev) Duplex() conn.Duplex {
return conn.Half
}
// Addr is an I²C slave address.
type Addr uint16
// Set sets the Addr to a value represented by the string s. Values maybe in
// decimal or hexadecimal form. Set implements the flag.Value interface.
func (a *Addr) Set(s string) error {
// Allow for only maximum of 10 bits for i2c addresses.
u, err := strconv.ParseUint(s, 0, 10)
if err != nil {
return errI2CSetError
}
*a = Addr(u)
return nil
}
// String returns an i2c.Addr as a string formated in hexadecimal.
func (a Addr) String() string {
return "0x" + strconv.FormatInt(int64(a), 16)
}
var errI2CSetError = errors.New("invalid i2c address")
var _ conn.Conn = &Dev{}

252
vendor/periph.io/x/conn/v3/i2c/i2creg/i2creg.go generated vendored Normal file
View File

@ -0,0 +1,252 @@
// Copyright 2017 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package i2creg defines I²C bus registry to list buses present on the host.
package i2creg
import (
"errors"
"strconv"
"strings"
"sync"
"periph.io/x/conn/v3/i2c"
)
// Opener opens an handle to a bus.
//
// It is provided by the actual bus driver.
type Opener func() (i2c.BusCloser, error)
// Ref references an I²C bus.
//
// It is returned by All() to enumerate all registered buses.
type Ref struct {
// Name of the bus.
//
// It must not be a sole number. It must be unique across the host.
Name string
// Aliases are the alternative names that can be used to reference this bus.
Aliases []string
// Number of the bus or -1 if the bus doesn't have any "native" number.
//
// Buses provided by the CPU normally have a 0 based number. Buses provided
// via an addon (like over USB) generally are not numbered.
Number int
// Open is the factory to open an handle to this I²C bus.
Open Opener
}
// Open opens an I²C bus by its name, an alias or its number and returns an
// handle to it.
//
// Specify the empty string "" to get the first available bus. This is the
// recommended default value unless an application knows the exact bus to use.
//
// Each bus can register multiple aliases, each leading to the same bus handle.
//
// "Bus number" is a generic concept that is highly dependent on the platform
// and OS. On some platform, the first bus may have the number 0, 1 or higher.
// Bus numbers are not necessarily continuous and may not start at 0. It was
// observed that the bus number as reported by the OS may change across OS
// revisions.
//
// When the I²C bus is provided by an off board plug and play bus like USB via
// a FT232H USB device, there can be no associated number.
func Open(name string) (i2c.BusCloser, error) {
var r *Ref
var err error
func() {
mu.Lock()
defer mu.Unlock()
if len(byName) == 0 {
err = errors.New("i2creg: no bus found; did you forget to call Init()?")
return
}
if len(name) == 0 {
r = getDefault()
return
}
// Try by name, by alias, by number.
if r = byName[name]; r == nil {
if r = byAlias[name]; r == nil {
if i, err2 := strconv.Atoi(name); err2 == nil {
r = byNumber[i]
}
}
}
}()
if err != nil {
return nil, err
}
if r == nil {
return nil, errors.New("i2creg: can't open unknown bus: " + strconv.Quote(name))
}
return r.Open()
}
// All returns a copy of all the registered references to all know I²C buses
// available on this host.
//
// The list is sorted by the bus name.
func All() []*Ref {
mu.Lock()
defer mu.Unlock()
out := make([]*Ref, 0, len(byName))
for _, v := range byName {
r := &Ref{Name: v.Name, Aliases: make([]string, len(v.Aliases)), Number: v.Number, Open: v.Open}
copy(r.Aliases, v.Aliases)
out = insertRef(out, r)
}
return out
}
// Register registers an I²C bus.
//
// Registering the same bus name twice is an error, e.g. o.Name(). o.Number()
// can be -1 to signify that the bus doesn't have an inherent "bus number". A
// good example is a bus provided over a FT232H device connected on an USB bus.
// In this case, the bus name should be created from the serial number of the
// device for unique identification.
func Register(name string, aliases []string, number int, o Opener) error {
if len(name) == 0 {
return errors.New("i2creg: can't register a bus with no name")
}
if o == nil {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " with nil Opener")
}
if number < -1 {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " with invalid bus number " + strconv.Itoa(number))
}
if _, err := strconv.Atoi(name); err == nil {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " with name being only a number")
}
if strings.Contains(name, ":") {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " with name containing ':'")
}
for _, alias := range aliases {
if len(alias) == 0 {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " with an empty alias")
}
if name == alias {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " with an alias the same as the bus name")
}
if _, err := strconv.Atoi(alias); err == nil {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " with an alias that is a number: " + strconv.Quote(alias))
}
if strings.Contains(alias, ":") {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " with an alias containing ':': " + strconv.Quote(alias))
}
}
mu.Lock()
defer mu.Unlock()
if _, ok := byName[name]; ok {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " twice")
}
if _, ok := byAlias[name]; ok {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " twice; it is already an alias")
}
if number != -1 {
if _, ok := byNumber[number]; ok {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + "; bus number " + strconv.Itoa(number) + " is already registered")
}
}
for _, alias := range aliases {
if _, ok := byName[alias]; ok {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " twice; alias " + strconv.Quote(alias) + " is already a bus")
}
if _, ok := byAlias[alias]; ok {
return errors.New("i2creg: can't register bus " + strconv.Quote(name) + " twice; alias " + strconv.Quote(alias) + " is already an alias")
}
}
r := &Ref{Name: name, Aliases: make([]string, len(aliases)), Number: number, Open: o}
copy(r.Aliases, aliases)
byName[name] = r
if number != -1 {
byNumber[number] = r
}
for _, alias := range aliases {
byAlias[alias] = r
}
return nil
}
// Unregister removes a previously registered I²C bus.
//
// This can happen when an I²C bus is exposed via an USB device and the device
// is unplugged.
func Unregister(name string) error {
mu.Lock()
defer mu.Unlock()
r := byName[name]
if r == nil {
return errors.New("i2creg: can't unregister unknown bus name " + strconv.Quote(name))
}
delete(byName, name)
delete(byNumber, r.Number)
for _, alias := range r.Aliases {
delete(byAlias, alias)
}
return nil
}
//
var (
mu sync.Mutex
byName = map[string]*Ref{}
// Caches
byNumber = map[int]*Ref{}
byAlias = map[string]*Ref{}
)
// getDefault returns the Ref that should be used as the default bus.
func getDefault() *Ref {
var o *Ref
if len(byNumber) == 0 {
// Fallback to use byName using a lexical sort.
name := ""
for n, o2 := range byName {
if len(name) == 0 || n < name {
o = o2
name = n
}
}
return o
}
number := int((^uint(0)) >> 1)
for n, o2 := range byNumber {
if number > n {
number = n
o = o2
}
}
return o
}
func insertRef(l []*Ref, r *Ref) []*Ref {
n := r.Name
i := search(len(l), func(i int) bool { return l[i].Name > n })
l = append(l, nil)
copy(l[i+1:], l[i:])
l[i] = r
return l
}
// search implements the same algorithm as sort.Search().
//
// It was extracted to to not depend on sort, which depends on reflect.
func search(n int, f func(int) bool) int {
lo := 0
for hi := n; lo < hi; {
if i := int(uint(lo+hi) >> 1); !f(i) {
lo = i + 1
} else {
hi = i
}
}
return lo
}

21
vendor/periph.io/x/conn/v3/physic/doc.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package physic declares types for physical input, outputs and measurement
// units.
//
// This includes temperature, humidity, pressure, tension, current, etc.
//
// SI units
//
// The supported S.I. units is a subset of the official ones.
// T tera 10¹² 1000000000000
// G giga 10⁹ 1000000000
// M mega 10⁶ 1000000
// k kilo 10³ 1000
// m milli 10⁻³ 0.001
// µ,u micro 10⁻⁶ 0.000001
// n nano 10⁻⁹ 0.000000001
// p pico 10⁻¹² 0.000000000001
package physic

42
vendor/periph.io/x/conn/v3/physic/physic.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package physic
import (
"time"
"periph.io/x/conn/v3"
)
// Env represents measurements from an environmental sensor.
type Env struct {
Temperature Temperature
Pressure Pressure
Humidity RelativeHumidity
}
// SenseEnv represents an environmental sensor.
type SenseEnv interface {
conn.Resource
// Sense returns the value read from the sensor. Unsupported metrics are not
// modified.
Sense(env *Env) error
// SenseContinuous initiates a continuous sensing at the specified interval.
//
// It is important to call Halt() once done with the sensing, which will turn
// the device off and will close the channel.
SenseContinuous(interval time.Duration) (<-chan Env, error)
// Precision returns this sensor's precision.
//
// The env values are set to the number of bits that are significant for each
// items that this sensor can measure.
//
// Precision is not accuracy. The sensor may have absolute and relative
// errors in its measurement, that are likely well above the reported
// precision. Accuracy may be improved on some sensor by using oversampling,
// or doing oversampling in software. Refer to its datasheet if available.
Precision(env *Env)
}

2313
vendor/periph.io/x/conn/v3/physic/units.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

58
vendor/periph.io/x/conn/v3/pin/func.go generated vendored Normal file
View File

@ -0,0 +1,58 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package pin
import (
"strconv"
"strings"
)
// Func is a pin function.
//
// The Func format must be "[A-Z]+", "[A-Z]+_[A-Z]+" or exceptionally
// "(In|Out)/(Low|High)".
type Func string
// FuncNone is returned by PinFunc.Func() for a Pin without an active
// functionality.
const FuncNone Func = ""
// Specialize converts a "BUS_LINE" function and appends the bug number and
// line number, to look like "BUS0_LINE1".
//
// Use -1 to not add a bus or line number.
func (f Func) Specialize(b, l int) Func {
if f == FuncNone {
return FuncNone
}
if b != -1 {
parts := strings.SplitN(string(f), "_", 2)
if len(parts) == 1 {
return FuncNone
}
f = Func(parts[0] + strconv.Itoa(b) + "_" + parts[1])
}
if l != -1 {
f += Func(strconv.Itoa(l))
}
return f
}
// Generalize is the reverse of Specialize().
func (f Func) Generalize() Func {
parts := strings.SplitN(string(f), "_", 2)
f = Func(strings.TrimRightFunc(parts[0], isNum))
if len(parts) == 2 {
f += "_"
f += Func(strings.TrimRightFunc(parts[1], isNum))
}
return f
}
//
func isNum(r rune) bool {
return r >= '0' && r <= '9'
}

139
vendor/periph.io/x/conn/v3/pin/pin.go generated vendored Normal file
View File

@ -0,0 +1,139 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package pin declare well known pins.
//
// pin is about physical pins, not about their logical function.
//
// While not a protocol strictly speaking, these are "well known constants".
package pin
import (
"errors"
"periph.io/x/conn/v3"
)
// These are well known pins.
var (
INVALID *BasicPin // Either floating or invalid pin
GROUND *BasicPin // Ground
V1_8 *BasicPin // 1.8V (filtered)
V2_8 *BasicPin // 2.8V (filtered)
V3_3 *BasicPin // 3.3V (filtered)
V5 *BasicPin // 5V (filtered)
DC_IN *BasicPin // DC IN; this is normally the 5V input
BAT_PLUS *BasicPin // LiPo Battery + connector
)
// Pin is the minimal common interface shared between gpio.PinIO and
// analog.PinIO.
type Pin interface {
conn.Resource
// Name returns the name of the pin.
Name() string
// Number returns the logical pin number or a negative number if the pin is
// not a GPIO, e.g. GROUND, V3_3, etc.
Number() int
// Function returns a user readable string representation of what the pin is
// configured to do. Common case is In and Out but it can be bus specific pin
// name.
//
// Deprecated: Use PinFunc.Func. Will be removed in v4.
Function() string
}
// PinFunc is a supplementary interface that enables specifically querying for
// the pin function.
//
// TODO(maruel): It will be merged into interface Pin for v4.
type PinFunc interface {
// Func returns the pin's current function.
//
// The returned value may be specialized or generalized, depending on the
// actual port. For example it will likely be generalized for ports served
// over USB (like a FT232H with D0 set as SPI_MOSI) but specialized for
// ports on the base board (like a RPi3 with GPIO10 set as SPI0_MOSI).
Func() Func
// SupportedFuncs returns the possible functions this pin support.
//
// Do not mutate the returned slice.
SupportedFuncs() []Func
// SetFunc sets the pin function.
//
// Example use is to reallocate a RPi3's GPIO14 active function between
// UART0_TX and UART1_TX.
SetFunc(f Func) error
}
//
// BasicPin implements Pin as a static pin.
//
// It doesn't have a usable functionality.
type BasicPin struct {
N string
}
// String implements conn.Resource.
func (b *BasicPin) String() string {
return b.N
}
// Halt implements conn.Resource.
func (b *BasicPin) Halt() error {
return nil
}
// Name implements Pin.
func (b *BasicPin) Name() string {
return b.N
}
// Number implements Pin.
//
// Returns -1 as pin number.
func (b *BasicPin) Number() int {
return -1
}
// Function implements Pin.
//
// Returns "" as pin function.
func (b *BasicPin) Function() string {
return ""
}
// Func implements PinFunc.
//
// Returns FuncNone as pin function.
func (b *BasicPin) Func() Func {
return FuncNone
}
// SupportedFuncs implements PinFunc.
//
// Returns nil.
func (b *BasicPin) SupportedFuncs() []Func {
return nil
}
// SetFunc implements PinFunc.
func (b *BasicPin) SetFunc(f Func) error {
return errors.New("pin: can't change static pin function")
}
func init() {
INVALID = &BasicPin{N: "INVALID"}
GROUND = &BasicPin{N: "GROUND"}
V1_8 = &BasicPin{N: "1.8V"}
V2_8 = &BasicPin{N: "2.8V"}
V3_3 = &BasicPin{N: "3.3V"}
V5 = &BasicPin{N: "5V"}
DC_IN = &BasicPin{N: "DC_IN"}
BAT_PLUS = &BasicPin{N: "BAT+"}
}
var _ Pin = INVALID
var _ PinFunc = INVALID

7
vendor/periph.io/x/conn/v3/pin/pinreg/doc.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package pinreg is a registry for the physical headers (made up of pins) on
// a host.
package pinreg

148
vendor/periph.io/x/conn/v3/pin/pinreg/pinreg.go generated vendored Normal file
View File

@ -0,0 +1,148 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package pinreg
import (
"errors"
"strconv"
"sync"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
"periph.io/x/conn/v3/pin"
)
// All contains all the on-board headers on a micro computer.
//
// The map key is the header name, e.g. "P1" or "EULER" and the value is a
// slice of slice of pin.Pin. For a 2x20 header, it's going to be a slice of
// [20][2]pin.Pin.
func All() map[string][][]pin.Pin {
mu.Lock()
defer mu.Unlock()
out := make(map[string][][]pin.Pin, len(allHeaders))
for k, v := range allHeaders {
outV := make([][]pin.Pin, len(v))
for i, w := range v {
outW := make([]pin.Pin, len(w))
copy(outW, w)
outV[i] = outW
}
out[k] = outV
}
return out
}
// Position returns the position on a pin if found.
//
// The header and the pin number. Pin numbers are 1-based.
//
// Returns "", 0 if not connected.
func Position(p pin.Pin) (string, int) {
mu.Lock()
defer mu.Unlock()
pos := byPin[realPin(p).Name()]
return pos.name, pos.number
}
// IsConnected returns true if the pin is on a header.
func IsConnected(p pin.Pin) bool {
_, i := Position(p)
return i != 0
}
// Register registers a physical header.
//
// It automatically registers all gpio pins to gpioreg.
func Register(name string, allPins [][]pin.Pin) error {
mu.Lock()
defer mu.Unlock()
if _, ok := allHeaders[name]; ok {
return errors.New("pinreg: header " + strconv.Quote(name) + " was already registered")
}
for i, line := range allPins {
for j, pin := range line {
if pin == nil || len(pin.Name()) == 0 {
return errors.New("pinreg: invalid pin on header " + name + "[" + strconv.Itoa(i+1) + "][" + strconv.Itoa(j+1) + "]")
}
}
}
allHeaders[name] = allPins
number := 1
for _, line := range allPins {
for _, p := range line {
byPin[realPin(p).Name()] = position{name, number}
number++
}
}
count := 0
for _, row := range allPins {
for _, p := range row {
count++
if _, ok := p.(gpio.PinIO); ok {
if err := gpioreg.RegisterAlias(name+"_"+strconv.Itoa(count), p.Name()); err != nil {
// Unregister as much as possible.
_ = unregister(name)
return errors.New("pinreg: " + err.Error())
}
}
}
}
return nil
}
// Unregister removes a previously registered header.
//
// This can happen when an USB device, which exposed an header, is unplugged.
// This is also useful for unit testing.
func Unregister(name string) error {
mu.Lock()
defer mu.Unlock()
return unregister(name)
}
//
type position struct {
name string // Header name
number int // Pin number
}
var (
mu sync.Mutex
allHeaders = map[string][][]pin.Pin{} // every known headers as per internal lookup table
byPin = map[string]position{} // GPIO pin name to position
)
func unregister(name string) error {
if hdr, ok := allHeaders[name]; ok {
var err error
delete(allHeaders, name)
count := 0
for _, row := range hdr {
for _, p := range row {
count++
if _, ok := p.(gpio.PinIO); ok {
if err1 := gpioreg.Unregister(name + "_" + strconv.Itoa(count)); err1 != nil && err == nil {
// Continue unregistering as much as possible.
err = errors.New("pinreg: " + err1.Error())
}
}
}
}
return err
}
return errors.New("pinreg: can't unregister unknown header name " + strconv.Quote(name))
}
// realPin returns the real pin from an alias.
func realPin(p pin.Pin) pin.Pin {
if r, ok := p.(gpio.RealPin); ok {
p = r.Real()
}
return p
}

15
vendor/periph.io/x/conn/v3/spi/func.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package spi
import "periph.io/x/conn/v3/pin"
// Well known pin functionality.
const (
CLK pin.Func = "SPI_CLK" // Clock
CS pin.Func = "SPI_CS" // Chip select
MISO pin.Func = "SPI_MISO" // Master in
MOSI pin.Func = "SPI_MOSI" // Master out
)

187
vendor/periph.io/x/conn/v3/spi/spi.go generated vendored Normal file
View File

@ -0,0 +1,187 @@
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package spi defines the API to communicate with devices over the SPI
// protocol.
//
// As described in https://periph.io/x/conn/v3#hdr-Concepts, periph.io uses
// the concepts of Bus, Port and Conn.
//
// In the package spi, 'Bus' is not exposed, as it would be SPI bus number
// without a CS line, for example on linux asking for "/dev/spi0" without the
// ".0" suffix.
//
// The OS doesn't allow that so it is counter productive to express this at the
// API layer, so 'Port' is exposed directly instead.
//
// Use Port.Connect() converts the uninitialized Port into a Conn.
//
// See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface for more
// information.
package spi
import (
"io"
"strconv"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
// Mode determines how communication is done.
//
// The bits can be OR'ed to change the parameters used for
// communication.
//
type Mode int
// Mode determines the SPI communication parameters.
//
// CPOL means the clock polarity. Idle is High when set.
//
// CPHA is the clock phase, sample on trailing edge when set.
const (
Mode0 Mode = 0x0 // CPOL=0, CPHA=0
Mode1 Mode = 0x1 // CPOL=0, CPHA=1
Mode2 Mode = 0x2 // CPOL=1, CPHA=0
Mode3 Mode = 0x3 // CPOL=1, CPHA=1
// HalfDuplex specifies that MOSI and MISO use the same wire, and that only
// one duplex is used at a time.
HalfDuplex Mode = 0x4
// NoCS request the driver to not use the CS line.
NoCS Mode = 0x8
// LSBFirst requests the words to be encoded in little endian instead of the
// default big endian.
LSBFirst = 0x10
)
func (m Mode) String() string {
s := ""
switch m & Mode3 {
case Mode0:
s = "Mode0"
case Mode1:
s = "Mode1"
case Mode2:
s = "Mode2"
case Mode3:
s = "Mode3"
}
m &^= Mode3
if m&HalfDuplex != 0 {
s += "|HalfDuplex"
}
m &^= HalfDuplex
if m&NoCS != 0 {
s += "|NoCS"
}
m &^= NoCS
if m&LSBFirst != 0 {
s += "|LSBFirst"
}
m &^= LSBFirst
if m != 0 {
s += "|0x"
s += strconv.FormatUint(uint64(m), 16)
}
return s
}
// Packet represents one packet when sending multiple packets as a transaction.
type Packet struct {
// W and R are the output and input data. When HalfDuplex is specified to
// Connect, only one of the two can be set.
W, R []byte
// BitsPerWord overrides the default bits per word value set in Connect.
BitsPerWord uint8
// KeepCS tells the driver to keep CS asserted after this packet is
// completed. This can be leveraged to create long transaction as multiple
// packets like to use 9 bits commands then 8 bits data.
//
// Normally during a spi.Conn.TxPackets() call, KeepCS should be set to true
// for all packets except the last one. If the last one is set to true, the
// CS line stays asserted, leaving the transaction hanging on the bus.
//
// KeepCS is ignored when NoCS was specified to Connect.
KeepCS bool
}
// Conn defines the interface a concrete SPI driver must implement.
//
// Implementers can optionally implement io.Writer and io.Reader for
// unidirectional operation.
type Conn interface {
conn.Conn
// TxPackets does multiple operations over the SPI connection.
//
// The maximum number of bytes can be limited depending on the driver. Query
// conn.Limits.MaxTxSize() can be used to determine the limit.
//
// If the last packet has KeepCS:true, the CS line stays asserted. This
// enables doing SPI transaction over multiple calls.
//
// Conversely, if any packet beside the last one has KeepCS:false, the CS
// line will blip for a short amount of time to force a new transaction.
//
// It was observed on RPi3 hardware to have a one clock delay between each
// packet.
TxPackets(p []Packet) error
}
// Port is the interface to be provided to device drivers.
//
// The device driver, that is the driver for the peripheral connected over
// this port, calls Connect() to retrieve a configured connection as Conn.
type Port interface {
String() string
// Connect sets the communication parameters of the connection for use by a
// device.
//
// The device driver must call this function exactly once.
//
// f must specify the maximum rated speed by the device's spec. The lowest
// speed between the port speed and the device speed is selected. Use 0 for f
// if there is no known maximum value for this device.
//
// mode specifies the clock and signal polarities, if the port is using half
// duplex (shared MISO and MOSI) or if CS is not needed.
//
// bits is the number of bits per word. Generally you should use 8.
Connect(f physic.Frequency, mode Mode, bits int) (Conn, error)
}
// PortCloser is a SPI port that can be closed.
//
// This interface is meant to be handled by the application.
type PortCloser interface {
io.Closer
Port
// LimitSpeed sets the maximum port speed.
//
// It lets an application use a device at a lower speed than the maximum
// speed as rated by the device driver. This is useful for example when the
// wires are long or the connection is of poor quality.
//
// This function can be called multiple times and resets the previous value.
// 0 is not a valid value for f. The lowest speed between the port speed and
// the device speed is selected.
LimitSpeed(f physic.Frequency) error
}
// Pins defines the pins that a SPI port interconnect is using on the host.
//
// It is expected that a implementer of ConnCloser or Conn also implement Pins
// but this is not a requirement.
type Pins interface {
// CLK returns the SCK (clock) pin.
CLK() gpio.PinOut
// MOSI returns the SDO (master out, slave in) pin.
MOSI() gpio.PinOut
// MISO returns the SDI (master in, slave out) pin.
MISO() gpio.PinIn
// CS returns the CSN (chip select) pin.
CS() gpio.PinOut
}

262
vendor/periph.io/x/conn/v3/spi/spireg/spireg.go generated vendored Normal file
View File

@ -0,0 +1,262 @@
// Copyright 2017 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package spireg defines the SPI registry for SPI ports discovered on the host.
//
// SPI ports discovered on the host are automatically registered in the SPI
// registry by host.Init().
package spireg
import (
"errors"
"strconv"
"strings"
"sync"
"periph.io/x/conn/v3/spi"
)
// Opener opens an handle to a port.
//
// It is provided by the actual port driver.
type Opener func() (spi.PortCloser, error)
// Ref references a SPI port.
//
// It is returned by All() to enumerate all registered ports.
type Ref struct {
// Name of the port.
//
// It must not be a sole number. It must be unique across the host.
Name string
// Aliases are the alternative names that can be used to reference this port.
Aliases []string
// Number of the bus or -1 if the bus doesn't have any "native" number.
//
// Buses provided by the CPU normally have a 0 based number. Buses provided
// via an addon (like over USB) generally are not numbered.
//
// The port is a bus number plus a CS line.
Number int
// Open is the factory to open an handle to this SPI port.
Open Opener
}
// Open opens a SPI port by its name, an alias or its number and returns an
// handle to it.
//
// Specify the empty string "" to get the first available port. This is the
// recommended default value unless an application knows the exact port to use.
//
// Each port can register multiple aliases, each leading to the same port
// handle.
//
// "Bus number" is a generic concept that is highly dependent on the platform
// and OS. On some platform, the first port may have the number 0, 1 or as high
// as 32766. Bus numbers are not necessarily continuous and may not start at 0.
// It was observed that the bus number as reported by the OS may change across
// OS revisions.
//
// A SPI port is constructed of the bus number and the chip select (CS) number.
//
// When the SPI port is provided by an off board plug and play bus like USB via
// a FT232H USB device, there can be no associated number.
func Open(name string) (spi.PortCloser, error) {
var r *Ref
var err error
func() {
mu.Lock()
defer mu.Unlock()
if len(byName) == 0 {
err = errors.New("spireg: no port found; did you forget to call Init()?")
return
}
if len(name) == 0 {
r = getDefault()
return
}
// Try by name, by alias, by number.
if r = byName[name]; r == nil {
if r = byAlias[name]; r == nil {
if i, err2 := strconv.Atoi(name); err2 == nil {
r = byNumber[i]
}
}
}
}()
if err != nil {
return nil, err
}
if r == nil {
return nil, errors.New("spireg: can't open unknown port: " + strconv.Quote(name))
}
return r.Open()
}
// All returns a copy of all the registered references to all know SPI ports
// available on this host.
//
// The list is sorted by the port name.
func All() []*Ref {
mu.Lock()
defer mu.Unlock()
out := make([]*Ref, 0, len(byName))
for _, v := range byName {
r := &Ref{Name: v.Name, Aliases: make([]string, len(v.Aliases)), Number: v.Number, Open: v.Open}
copy(r.Aliases, v.Aliases)
out = insertRef(out, r)
}
return out
}
// Register registers a SPI port.
//
// Registering the same port name twice is an error, e.g. o.Name(). o.Number()
// can be -1 to signify that the port doesn't have an inherent "bus number". A
// good example is a port provided over a FT232H device connected on an USB bus.
// In this case, the port name should be created from the serial number of the
// device for unique identification.
//
// Only ports with the CS #0 are registered with their number.
func Register(name string, aliases []string, number int, o Opener) error {
if len(name) == 0 {
return errors.New("spireg: can't register a port with no name")
}
if o == nil {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " with nil Opener")
}
if number < -1 {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " with invalid port number " + strconv.Itoa(number))
}
if _, err := strconv.Atoi(name); err == nil {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " with name being only a number")
}
if strings.Contains(name, ":") {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " with name containing ':'")
}
for _, alias := range aliases {
if len(alias) == 0 {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " with an empty alias")
}
if name == alias {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " with an alias the same as the port name")
}
if _, err := strconv.Atoi(alias); err == nil {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " with an alias that is a number: " + strconv.Quote(alias))
}
if strings.Contains(alias, ":") {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " with an alias containing ':': " + strconv.Quote(alias))
}
}
mu.Lock()
defer mu.Unlock()
if _, ok := byName[name]; ok {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " twice")
}
if _, ok := byAlias[name]; ok {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " twice; it is already an alias")
}
if number != -1 {
if _, ok := byNumber[number]; ok {
return errors.New("spireg: can't register port " + strconv.Quote(name) + "; port number " + strconv.Itoa(number) + " is already registered")
}
}
for _, alias := range aliases {
if _, ok := byName[alias]; ok {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " twice; alias " + strconv.Quote(alias) + " is already a port")
}
if _, ok := byAlias[alias]; ok {
return errors.New("spireg: can't register port " + strconv.Quote(name) + " twice; alias " + strconv.Quote(alias) + " is already an alias")
}
}
r := &Ref{Name: name, Aliases: make([]string, len(aliases)), Number: number, Open: o}
copy(r.Aliases, aliases)
byName[name] = r
if number != -1 {
byNumber[number] = r
}
for _, alias := range aliases {
byAlias[alias] = r
}
return nil
}
// Unregister removes a previously registered SPI port.
//
// This can happen when a SPI port is exposed via an USB device and the device
// is unplugged.
func Unregister(name string) error {
mu.Lock()
defer mu.Unlock()
r := byName[name]
if r == nil {
return errors.New("spireg: can't unregister unknown port name " + strconv.Quote(name))
}
delete(byName, name)
delete(byNumber, r.Number)
for _, alias := range r.Aliases {
delete(byAlias, alias)
}
return nil
}
//
var (
mu sync.Mutex
byName = map[string]*Ref{}
// Caches
byNumber = map[int]*Ref{}
byAlias = map[string]*Ref{}
)
// getDefault returns the Ref that should be used as the default port.
func getDefault() *Ref {
var o *Ref
if len(byNumber) == 0 {
// Fallback to use byName using a lexical sort.
name := ""
for n, o2 := range byName {
if len(name) == 0 || n < name {
o = o2
name = n
}
}
return o
}
number := int((^uint(0)) >> 1)
for n, o2 := range byNumber {
if number > n {
number = n
o = o2
}
}
return o
}
func insertRef(l []*Ref, r *Ref) []*Ref {
n := r.Name
i := search(len(l), func(i int) bool { return l[i].Name > n })
l = append(l, nil)
copy(l[i+1:], l[i:])
l[i] = r
return l
}
// search implements the same algorithm as sort.Search().
//
// It was extracted to to not depend on sort, which depends on reflect.
func search(n int, f func(int) bool) int {
lo := 0
for hi := n; lo < hi; {
if i := int(uint(lo+hi) >> 1); !f(i) {
lo = i + 1
} else {
hi = i
}
}
return lo
}