First implementation
This commit is contained in:
103
vendor/periph.io/x/periph/conn/conn.go
generated
vendored
Normal file
103
vendor/periph.io/x/periph/conn/conn.go
generated
vendored
Normal 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/periph/conn/doc.go
generated
vendored
Normal file
63
vendor/periph.io/x/periph/conn/doc.go
generated
vendored
Normal 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
|
3
vendor/periph.io/x/periph/conn/duplex_string.go
generated
vendored
Normal file
3
vendor/periph.io/x/periph/conn/duplex_string.go
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
// Code generated by "stringer -type Duplex"; DO NOT EDIT
|
||||
|
||||
package conn
|
26
vendor/periph.io/x/periph/conn/gpio/func.go
generated
vendored
Normal file
26
vendor/periph.io/x/periph/conn/gpio/func.go
generated
vendored
Normal 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/periph/conn/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/periph/conn/gpio/gpio.go
generated
vendored
Normal file
329
vendor/periph.io/x/periph/conn/gpio/gpio.go
generated
vendored
Normal 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/periph/conn/physic"
|
||||
"periph.io/x/periph/conn/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/periph/conn/gpio/gpioreg/gpioreg.go
generated
vendored
Normal file
213
vendor/periph.io/x/periph/conn/gpio/gpioreg/gpioreg.go
generated
vendored
Normal 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/periph/conn/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/periph/conn/gpio/gpioreg/natsort.go
generated
vendored
Normal file
76
vendor/periph.io/x/periph/conn/gpio/gpioreg/natsort.go
generated
vendored
Normal 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)
|
||||
}
|
220
vendor/periph.io/x/periph/conn/gpio/gpiostream/gpiostream.go
generated
vendored
Normal file
220
vendor/periph.io/x/periph/conn/gpio/gpiostream/gpiostream.go
generated
vendored
Normal 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/periph/conn/gpio"
|
||||
"periph.io/x/periph/conn/physic"
|
||||
"periph.io/x/periph/conn/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/periph/conn/i2c/func.go
generated
vendored
Normal file
13
vendor/periph.io/x/periph/conn/i2c/func.go
generated
vendored
Normal 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/periph/conn/pin"
|
||||
|
||||
// Well known pin functionality.
|
||||
const (
|
||||
SCL pin.Func = "I2C_SCL" // Clock
|
||||
SDA pin.Func = "I2C_SDA" // Data
|
||||
)
|
135
vendor/periph.io/x/periph/conn/i2c/i2c.go
generated
vendored
Normal file
135
vendor/periph.io/x/periph/conn/i2c/i2c.go
generated
vendored
Normal 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/periph/conn#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/periph/conn"
|
||||
"periph.io/x/periph/conn/gpio"
|
||||
"periph.io/x/periph/conn/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/periph/conn/i2c/i2creg/i2creg.go
generated
vendored
Normal file
252
vendor/periph.io/x/periph/conn/i2c/i2creg/i2creg.go
generated
vendored
Normal 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/periph/conn/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/periph/conn/physic/doc.go
generated
vendored
Normal file
21
vendor/periph.io/x/periph/conn/physic/doc.go
generated
vendored
Normal 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/periph/conn/physic/physic.go
generated
vendored
Normal file
42
vendor/periph.io/x/periph/conn/physic/physic.go
generated
vendored
Normal 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/periph/conn"
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
2254
vendor/periph.io/x/periph/conn/physic/units.go
generated
vendored
Normal file
2254
vendor/periph.io/x/periph/conn/physic/units.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
58
vendor/periph.io/x/periph/conn/pin/func.go
generated
vendored
Normal file
58
vendor/periph.io/x/periph/conn/pin/func.go
generated
vendored
Normal 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/periph/conn/pin/pin.go
generated
vendored
Normal file
139
vendor/periph.io/x/periph/conn/pin/pin.go
generated
vendored
Normal 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/periph/conn"
|
||||
)
|
||||
|
||||
// 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/periph/conn/pin/pinreg/doc.go
generated
vendored
Normal file
7
vendor/periph.io/x/periph/conn/pin/pinreg/doc.go
generated
vendored
Normal 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/periph/conn/pin/pinreg/pinreg.go
generated
vendored
Normal file
148
vendor/periph.io/x/periph/conn/pin/pinreg/pinreg.go
generated
vendored
Normal 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/periph/conn/gpio"
|
||||
"periph.io/x/periph/conn/gpio/gpioreg"
|
||||
"periph.io/x/periph/conn/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/periph/conn/spi/func.go
generated
vendored
Normal file
15
vendor/periph.io/x/periph/conn/spi/func.go
generated
vendored
Normal 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/periph/conn/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/periph/conn/spi/spi.go
generated
vendored
Normal file
187
vendor/periph.io/x/periph/conn/spi/spi.go
generated
vendored
Normal 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/periph/conn#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/periph/conn"
|
||||
"periph.io/x/periph/conn/gpio"
|
||||
"periph.io/x/periph/conn/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/periph/conn/spi/spireg/spireg.go
generated
vendored
Normal file
262
vendor/periph.io/x/periph/conn/spi/spireg/spireg.go
generated
vendored
Normal 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/periph/conn/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
|
||||
}
|
Reference in New Issue
Block a user