Compare commits

..

No commits in common. "396d8a99b601476d895cda4ea369769534fd9c31" and "187735eee6a4b356136a3e1e7e512fe848cf627c" have entirely different histories.

91 changed files with 14056 additions and 581 deletions

13
go.mod
View File

@ -3,19 +3,20 @@ module github.com/cyrilix/robocar-led
go 1.17
require (
github.com/cyrilix/robocar-base v0.1.6
github.com/cyrilix/robocar-protobuf/go v1.0.4
github.com/cyrilix/robocar-base v0.1.5
github.com/cyrilix/robocar-protobuf/go v1.0.3
github.com/eclipse/paho.mqtt.golang v1.3.5
github.com/golang/protobuf v1.5.2
go.uber.org/zap v1.19.1
google.golang.org/protobuf v1.27.1
periph.io/x/conn/v3 v3.6.10
periph.io/x/host/v3 v3.7.2
periph.io/x/conn/v3 v3.6.8
periph.io/x/host/v3 v3.7.0
)
require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
google.golang.org/protobuf v1.26.0 // indirect
periph.io/x/d2xx v0.0.3 // indirect
)

25
go.sum
View File

@ -8,10 +8,10 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/cyrilix/robocar-base v0.1.6 h1:VVcSZD8DPsha3XDLxRBMvtcd6uC8CcIjqbxG482dxvo=
github.com/cyrilix/robocar-base v0.1.6/go.mod h1:m5ov/7hpRHi0yMp2prKafL6UEsM2O71Uea85WR0/jjI=
github.com/cyrilix/robocar-protobuf/go v1.0.4 h1:XTolFYbiKw4gQ2l+z/LMZkLrmAUMzlHcQBzp/czlANo=
github.com/cyrilix/robocar-protobuf/go v1.0.4/go.mod h1:1fyGMVm4ZodfYRrbWCEQgtvKyvrhyTBe5zA7/Qeh/H0=
github.com/cyrilix/robocar-base v0.1.5 h1:EfbYHB69hgyQCVuzZ9/ifdSrQfXS7+04M8O9BDu1/5w=
github.com/cyrilix/robocar-base v0.1.5/go.mod h1:tb7R5OFoBn9EWNLX3Kzx6R/3cQ9/7r8XsHvlLSESOAM=
github.com/cyrilix/robocar-protobuf/go v1.0.3 h1:iPHw2+7FVXG2C4+Th1m11hQ+2RpAQzlxKhc5M7XOa6Q=
github.com/cyrilix/robocar-protobuf/go v1.0.3/go.mod h1:xb95cK07lYXnKcHZKnGafmAgYRrqZWZgV9LMiJAp+gE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -48,8 +48,6 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -145,9 +143,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
@ -162,8 +159,10 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v0.0.0-20181223230014-1083505acf35/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
periph.io/x/conn/v3 v3.6.10 h1:gwU4ssmZkq1D/uz8hU91i/COo2c9DrRaS4PJZBbCd+c=
periph.io/x/conn/v3 v3.6.10/go.mod h1:UqWNaPMosWmNCwtufoTSTTYhB2wXWsMRAJyo1PlxO4Q=
periph.io/x/d2xx v0.0.4/go.mod h1:38Euaaj+s6l0faIRHh32a+PrjXvxFTFkPBEQI0TKg34=
periph.io/x/host/v3 v3.7.2 h1:rCAUxkzy2xrzh18HP2AoVwTL/fEKqmcJ1icsZQGM58Q=
periph.io/x/host/v3 v3.7.2/go.mod h1:nHMlzkPwmnHyP9Tn0I8FV+e0N3K7TjFXLZkIWzAicog=
periph.io/x/conn/v3 v3.6.8 h1:fnNSwSoKPzpoLOSxml70EInaP6YrrqcucP3KDfNxpmU=
periph.io/x/conn/v3 v3.6.8/go.mod h1:3OD27w9YVa5DS97VsUxsPGzD9Qrm5Ny7cF5b6xMMIWg=
periph.io/x/d2xx v0.0.1/go.mod h1:38Euaaj+s6l0faIRHh32a+PrjXvxFTFkPBEQI0TKg34=
periph.io/x/d2xx v0.0.3 h1:BE8XcIdxabu9ZzAr1UXxSz88T9Txki6Xyo8aJ1qZvks=
periph.io/x/d2xx v0.0.3/go.mod h1:38Euaaj+s6l0faIRHh32a+PrjXvxFTFkPBEQI0TKg34=
periph.io/x/host/v3 v3.7.0 h1:9CP/j0FcJmR+PRHlNzAmhV6Mt3GXoWnPmRhknJlQhnE=
periph.io/x/host/v3 v3.7.0/go.mod h1:okb5m0yUYLTM/dnMYWMBX47w4owTzyCPLpZUQb35nhs=

View File

@ -118,7 +118,7 @@ func (l *PiColorLed) blink(freq float64) {
ticker := time.NewTicker(time.Duration(float64(time.Second) / freq))
// Restore values
defer l.on()
defer l.SetColor(l.Color())
for {
select {

View File

@ -6,8 +6,8 @@ import (
"github.com/cyrilix/robocar-led/pkg/led"
"github.com/cyrilix/robocar-protobuf/go/events"
mqtt "github.com/eclipse/paho.mqtt.golang"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"sync"
"time"
)

View File

@ -2,21 +2,16 @@ package part
import (
"github.com/cyrilix/robocar-base/testtools"
"github.com/cyrilix/robocar-led/pkg/led"
"github.com/cyrilix/robocar-protobuf/go/events"
mqtt "github.com/eclipse/paho.mqtt.golang"
"google.golang.org/protobuf/proto"
"github.com/golang/protobuf/proto"
"testing"
"time"
)
type fakeLed struct {
color led.Color
blink bool
}
func (f *fakeLed) SetColor(color led.Color) {
f.color = color
red, green, blue int
blink bool
}
func (f *fakeLed) SetBlink(freq float64) {
@ -27,17 +22,29 @@ func (f *fakeLed) SetBlink(freq float64) {
}
}
func (f *fakeLed) SetRed(value int) {
f.red = value
}
func (f *fakeLed) SetGreen(value int) {
f.green = value
}
func (f *fakeLed) SetBlue(value int) {
f.blue = value
}
func TestLedPart_OnDriveMode(t *testing.T) {
l := fakeLed{}
p := LedPart{led: &l}
led := fakeLed{}
p := LedPart{led: &led}
cases := []struct {
msg mqtt.Message
color led.Color
msg mqtt.Message
red, green, blue int
}{
{testtools.NewFakeMessageFromProtobuf("drive", &events.DriveModeMessage{DriveMode: events.DriveMode_USER}), led.ColorGreen},
{testtools.NewFakeMessageFromProtobuf("drive", &events.DriveModeMessage{DriveMode: events.DriveMode_PILOT}), led.ColorBlue},
{testtools.NewFakeMessageFromProtobuf("drive", &events.DriveModeMessage{DriveMode: events.DriveMode_INVALID}), led.ColorBlue},
{testtools.NewFakeMessageFromProtobuf("drive", &events.DriveModeMessage{DriveMode: events.DriveMode_USER}), 0, 255, 0},
{testtools.NewFakeMessageFromProtobuf("drive", &events.DriveModeMessage{DriveMode: events.DriveMode_PILOT}), 0, 0, 255},
{testtools.NewFakeMessageFromProtobuf("drive", &events.DriveModeMessage{DriveMode: events.DriveMode_INVALID}), 0, 0, 255},
}
for _, c := range cases {
@ -49,8 +56,20 @@ func TestLedPart_OnDriveMode(t *testing.T) {
t.Errorf("unable to unmarshal drive mode message: %v", err)
}
value := msg.DriveMode
if l.color != c.color {
t.Errorf("driveMode(%v)=invalid value for color: %v, wants %v", value, l.color, c.color)
if led.red != c.red {
t.Errorf("driveMode(%v)=invalid value for red channel: %v, wants %v", value, led.red, c.red)
}
if led.green != c.green {
if err != nil {
t.Errorf("payload isn't a led value: %v", err)
}
t.Errorf("driveMode(%v)=invalid value for green channel: %v, wants %v", value, led.green, c.green)
}
if led.blue != c.blue {
if err != nil {
t.Errorf("payload isn't a led value: %v", err)
}
t.Errorf("driveMode(%v)=invalid value for blue channel: %v, wants %v", value, led.blue, c.blue)
}
}
}

View File

@ -2,8 +2,8 @@ package testtools
import (
mqtt "github.com/eclipse/paho.mqtt.golang"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
)
type fakeMessage struct {

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc-gen-go v1.26.0
// protoc v3.12.4
// source: events/events.proto

324
vendor/github.com/golang/protobuf/proto/buffer.go generated vendored Normal file
View File

@ -0,0 +1,324 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"errors"
"fmt"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/runtime/protoimpl"
)
const (
WireVarint = 0
WireFixed32 = 5
WireFixed64 = 1
WireBytes = 2
WireStartGroup = 3
WireEndGroup = 4
)
// EncodeVarint returns the varint encoded bytes of v.
func EncodeVarint(v uint64) []byte {
return protowire.AppendVarint(nil, v)
}
// SizeVarint returns the length of the varint encoded bytes of v.
// This is equal to len(EncodeVarint(v)).
func SizeVarint(v uint64) int {
return protowire.SizeVarint(v)
}
// DecodeVarint parses a varint encoded integer from b,
// returning the integer value and the length of the varint.
// It returns (0, 0) if there is a parse error.
func DecodeVarint(b []byte) (uint64, int) {
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, 0
}
return v, n
}
// Buffer is a buffer for encoding and decoding the protobuf wire format.
// It may be reused between invocations to reduce memory usage.
type Buffer struct {
buf []byte
idx int
deterministic bool
}
// NewBuffer allocates a new Buffer initialized with buf,
// where the contents of buf are considered the unread portion of the buffer.
func NewBuffer(buf []byte) *Buffer {
return &Buffer{buf: buf}
}
// SetDeterministic specifies whether to use deterministic serialization.
//
// Deterministic serialization guarantees that for a given binary, equal
// messages will always be serialized to the same bytes. This implies:
//
// - Repeated serialization of a message will return the same bytes.
// - Different processes of the same binary (which may be executing on
// different machines) will serialize equal messages to the same bytes.
//
// Note that the deterministic serialization is NOT canonical across
// languages. It is not guaranteed to remain stable over time. It is unstable
// across different builds with schema changes due to unknown fields.
// Users who need canonical serialization (e.g., persistent storage in a
// canonical form, fingerprinting, etc.) should define their own
// canonicalization specification and implement their own serializer rather
// than relying on this API.
//
// If deterministic serialization is requested, map entries will be sorted
// by keys in lexographical order. This is an implementation detail and
// subject to change.
func (b *Buffer) SetDeterministic(deterministic bool) {
b.deterministic = deterministic
}
// SetBuf sets buf as the internal buffer,
// where the contents of buf are considered the unread portion of the buffer.
func (b *Buffer) SetBuf(buf []byte) {
b.buf = buf
b.idx = 0
}
// Reset clears the internal buffer of all written and unread data.
func (b *Buffer) Reset() {
b.buf = b.buf[:0]
b.idx = 0
}
// Bytes returns the internal buffer.
func (b *Buffer) Bytes() []byte {
return b.buf
}
// Unread returns the unread portion of the buffer.
func (b *Buffer) Unread() []byte {
return b.buf[b.idx:]
}
// Marshal appends the wire-format encoding of m to the buffer.
func (b *Buffer) Marshal(m Message) error {
var err error
b.buf, err = marshalAppend(b.buf, m, b.deterministic)
return err
}
// Unmarshal parses the wire-format message in the buffer and
// places the decoded results in m.
// It does not reset m before unmarshaling.
func (b *Buffer) Unmarshal(m Message) error {
err := UnmarshalMerge(b.Unread(), m)
b.idx = len(b.buf)
return err
}
type unknownFields struct{ XXX_unrecognized protoimpl.UnknownFields }
func (m *unknownFields) String() string { panic("not implemented") }
func (m *unknownFields) Reset() { panic("not implemented") }
func (m *unknownFields) ProtoMessage() { panic("not implemented") }
// DebugPrint dumps the encoded bytes of b with a header and footer including s
// to stdout. This is only intended for debugging.
func (*Buffer) DebugPrint(s string, b []byte) {
m := MessageReflect(new(unknownFields))
m.SetUnknown(b)
b, _ = prototext.MarshalOptions{AllowPartial: true, Indent: "\t"}.Marshal(m.Interface())
fmt.Printf("==== %s ====\n%s==== %s ====\n", s, b, s)
}
// EncodeVarint appends an unsigned varint encoding to the buffer.
func (b *Buffer) EncodeVarint(v uint64) error {
b.buf = protowire.AppendVarint(b.buf, v)
return nil
}
// EncodeZigzag32 appends a 32-bit zig-zag varint encoding to the buffer.
func (b *Buffer) EncodeZigzag32(v uint64) error {
return b.EncodeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31))))
}
// EncodeZigzag64 appends a 64-bit zig-zag varint encoding to the buffer.
func (b *Buffer) EncodeZigzag64(v uint64) error {
return b.EncodeVarint(uint64((uint64(v) << 1) ^ uint64((int64(v) >> 63))))
}
// EncodeFixed32 appends a 32-bit little-endian integer to the buffer.
func (b *Buffer) EncodeFixed32(v uint64) error {
b.buf = protowire.AppendFixed32(b.buf, uint32(v))
return nil
}
// EncodeFixed64 appends a 64-bit little-endian integer to the buffer.
func (b *Buffer) EncodeFixed64(v uint64) error {
b.buf = protowire.AppendFixed64(b.buf, uint64(v))
return nil
}
// EncodeRawBytes appends a length-prefixed raw bytes to the buffer.
func (b *Buffer) EncodeRawBytes(v []byte) error {
b.buf = protowire.AppendBytes(b.buf, v)
return nil
}
// EncodeStringBytes appends a length-prefixed raw bytes to the buffer.
// It does not validate whether v contains valid UTF-8.
func (b *Buffer) EncodeStringBytes(v string) error {
b.buf = protowire.AppendString(b.buf, v)
return nil
}
// EncodeMessage appends a length-prefixed encoded message to the buffer.
func (b *Buffer) EncodeMessage(m Message) error {
var err error
b.buf = protowire.AppendVarint(b.buf, uint64(Size(m)))
b.buf, err = marshalAppend(b.buf, m, b.deterministic)
return err
}
// DecodeVarint consumes an encoded unsigned varint from the buffer.
func (b *Buffer) DecodeVarint() (uint64, error) {
v, n := protowire.ConsumeVarint(b.buf[b.idx:])
if n < 0 {
return 0, protowire.ParseError(n)
}
b.idx += n
return uint64(v), nil
}
// DecodeZigzag32 consumes an encoded 32-bit zig-zag varint from the buffer.
func (b *Buffer) DecodeZigzag32() (uint64, error) {
v, err := b.DecodeVarint()
if err != nil {
return 0, err
}
return uint64((uint32(v) >> 1) ^ uint32((int32(v&1)<<31)>>31)), nil
}
// DecodeZigzag64 consumes an encoded 64-bit zig-zag varint from the buffer.
func (b *Buffer) DecodeZigzag64() (uint64, error) {
v, err := b.DecodeVarint()
if err != nil {
return 0, err
}
return uint64((uint64(v) >> 1) ^ uint64((int64(v&1)<<63)>>63)), nil
}
// DecodeFixed32 consumes a 32-bit little-endian integer from the buffer.
func (b *Buffer) DecodeFixed32() (uint64, error) {
v, n := protowire.ConsumeFixed32(b.buf[b.idx:])
if n < 0 {
return 0, protowire.ParseError(n)
}
b.idx += n
return uint64(v), nil
}
// DecodeFixed64 consumes a 64-bit little-endian integer from the buffer.
func (b *Buffer) DecodeFixed64() (uint64, error) {
v, n := protowire.ConsumeFixed64(b.buf[b.idx:])
if n < 0 {
return 0, protowire.ParseError(n)
}
b.idx += n
return uint64(v), nil
}
// DecodeRawBytes consumes a length-prefixed raw bytes from the buffer.
// If alloc is specified, it returns a copy the raw bytes
// rather than a sub-slice of the buffer.
func (b *Buffer) DecodeRawBytes(alloc bool) ([]byte, error) {
v, n := protowire.ConsumeBytes(b.buf[b.idx:])
if n < 0 {
return nil, protowire.ParseError(n)
}
b.idx += n
if alloc {
v = append([]byte(nil), v...)
}
return v, nil
}
// DecodeStringBytes consumes a length-prefixed raw bytes from the buffer.
// It does not validate whether the raw bytes contain valid UTF-8.
func (b *Buffer) DecodeStringBytes() (string, error) {
v, n := protowire.ConsumeString(b.buf[b.idx:])
if n < 0 {
return "", protowire.ParseError(n)
}
b.idx += n
return v, nil
}
// DecodeMessage consumes a length-prefixed message from the buffer.
// It does not reset m before unmarshaling.
func (b *Buffer) DecodeMessage(m Message) error {
v, err := b.DecodeRawBytes(false)
if err != nil {
return err
}
return UnmarshalMerge(v, m)
}
// DecodeGroup consumes a message group from the buffer.
// It assumes that the start group marker has already been consumed and
// consumes all bytes until (and including the end group marker).
// It does not reset m before unmarshaling.
func (b *Buffer) DecodeGroup(m Message) error {
v, n, err := consumeGroup(b.buf[b.idx:])
if err != nil {
return err
}
b.idx += n
return UnmarshalMerge(v, m)
}
// consumeGroup parses b until it finds an end group marker, returning
// the raw bytes of the message (excluding the end group marker) and the
// the total length of the message (including the end group marker).
func consumeGroup(b []byte) ([]byte, int, error) {
b0 := b
depth := 1 // assume this follows a start group marker
for {
_, wtyp, tagLen := protowire.ConsumeTag(b)
if tagLen < 0 {
return nil, 0, protowire.ParseError(tagLen)
}
b = b[tagLen:]
var valLen int
switch wtyp {
case protowire.VarintType:
_, valLen = protowire.ConsumeVarint(b)
case protowire.Fixed32Type:
_, valLen = protowire.ConsumeFixed32(b)
case protowire.Fixed64Type:
_, valLen = protowire.ConsumeFixed64(b)
case protowire.BytesType:
_, valLen = protowire.ConsumeBytes(b)
case protowire.StartGroupType:
depth++
case protowire.EndGroupType:
depth--
default:
return nil, 0, errors.New("proto: cannot parse reserved wire type")
}
if valLen < 0 {
return nil, 0, protowire.ParseError(valLen)
}
b = b[valLen:]
if depth == 0 {
return b0[:len(b0)-len(b)-tagLen], len(b0) - len(b), nil
}
}
}

63
vendor/github.com/golang/protobuf/proto/defaults.go generated vendored Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// SetDefaults sets unpopulated scalar fields to their default values.
// Fields within a oneof are not set even if they have a default value.
// SetDefaults is recursively called upon any populated message fields.
func SetDefaults(m Message) {
if m != nil {
setDefaults(MessageReflect(m))
}
}
func setDefaults(m protoreflect.Message) {
fds := m.Descriptor().Fields()
for i := 0; i < fds.Len(); i++ {
fd := fds.Get(i)
if !m.Has(fd) {
if fd.HasDefault() && fd.ContainingOneof() == nil {
v := fd.Default()
if fd.Kind() == protoreflect.BytesKind {
v = protoreflect.ValueOf(append([]byte(nil), v.Bytes()...)) // copy the default bytes
}
m.Set(fd, v)
}
continue
}
}
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
switch {
// Handle singular message.
case fd.Cardinality() != protoreflect.Repeated:
if fd.Message() != nil {
setDefaults(m.Get(fd).Message())
}
// Handle list of messages.
case fd.IsList():
if fd.Message() != nil {
ls := m.Get(fd).List()
for i := 0; i < ls.Len(); i++ {
setDefaults(ls.Get(i).Message())
}
}
// Handle map of messages.
case fd.IsMap():
if fd.MapValue().Message() != nil {
ms := m.Get(fd).Map()
ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
setDefaults(v.Message())
return true
})
}
}
return true
})
}

113
vendor/github.com/golang/protobuf/proto/deprecated.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"encoding/json"
"errors"
"fmt"
"strconv"
protoV2 "google.golang.org/protobuf/proto"
)
var (
// Deprecated: No longer returned.
ErrNil = errors.New("proto: Marshal called with nil")
// Deprecated: No longer returned.
ErrTooLarge = errors.New("proto: message encodes to over 2 GB")
// Deprecated: No longer returned.
ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
)
// Deprecated: Do not use.
type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
// Deprecated: Do not use.
func GetStats() Stats { return Stats{} }
// Deprecated: Do not use.
func MarshalMessageSet(interface{}) ([]byte, error) {
return nil, errors.New("proto: not implemented")
}
// Deprecated: Do not use.
func UnmarshalMessageSet([]byte, interface{}) error {
return errors.New("proto: not implemented")
}
// Deprecated: Do not use.
func MarshalMessageSetJSON(interface{}) ([]byte, error) {
return nil, errors.New("proto: not implemented")
}
// Deprecated: Do not use.
func UnmarshalMessageSetJSON([]byte, interface{}) error {
return errors.New("proto: not implemented")
}
// Deprecated: Do not use.
func RegisterMessageSetType(Message, int32, string) {}
// Deprecated: Do not use.
func EnumName(m map[int32]string, v int32) string {
s, ok := m[v]
if ok {
return s
}
return strconv.Itoa(int(v))
}
// Deprecated: Do not use.
func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
if data[0] == '"' {
// New style: enums are strings.
var repr string
if err := json.Unmarshal(data, &repr); err != nil {
return -1, err
}
val, ok := m[repr]
if !ok {
return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
}
return val, nil
}
// Old style: enums are ints.
var val int32
if err := json.Unmarshal(data, &val); err != nil {
return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
}
return val, nil
}
// Deprecated: Do not use; this type existed for intenal-use only.
type InternalMessageInfo struct{}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) DiscardUnknown(m Message) {
DiscardUnknown(m)
}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) Marshal(b []byte, m Message, deterministic bool) ([]byte, error) {
return protoV2.MarshalOptions{Deterministic: deterministic}.MarshalAppend(b, MessageV2(m))
}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) Merge(dst, src Message) {
protoV2.Merge(MessageV2(dst), MessageV2(src))
}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) Size(m Message) int {
return protoV2.Size(MessageV2(m))
}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) Unmarshal(m Message, b []byte) error {
return protoV2.UnmarshalOptions{Merge: true}.Unmarshal(b, MessageV2(m))
}

58
vendor/github.com/golang/protobuf/proto/discard.go generated vendored Normal file
View File

@ -0,0 +1,58 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// DiscardUnknown recursively discards all unknown fields from this message
// and all embedded messages.
//
// When unmarshaling a message with unrecognized fields, the tags and values
// of such fields are preserved in the Message. This allows a later call to
// marshal to be able to produce a message that continues to have those
// unrecognized fields. To avoid this, DiscardUnknown is used to
// explicitly clear the unknown fields after unmarshaling.
func DiscardUnknown(m Message) {
if m != nil {
discardUnknown(MessageReflect(m))
}
}
func discardUnknown(m protoreflect.Message) {
m.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool {
switch {
// Handle singular message.
case fd.Cardinality() != protoreflect.Repeated:
if fd.Message() != nil {
discardUnknown(m.Get(fd).Message())
}
// Handle list of messages.
case fd.IsList():
if fd.Message() != nil {
ls := m.Get(fd).List()
for i := 0; i < ls.Len(); i++ {
discardUnknown(ls.Get(i).Message())
}
}
// Handle map of messages.
case fd.IsMap():
if fd.MapValue().Message() != nil {
ms := m.Get(fd).Map()
ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
discardUnknown(v.Message())
return true
})
}
}
return true
})
// Discard unknown fields.
if len(m.GetUnknown()) > 0 {
m.SetUnknown(nil)
}
}

356
vendor/github.com/golang/protobuf/proto/extensions.go generated vendored Normal file
View File

@ -0,0 +1,356 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"errors"
"fmt"
"reflect"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/runtime/protoiface"
"google.golang.org/protobuf/runtime/protoimpl"
)
type (
// ExtensionDesc represents an extension descriptor and
// is used to interact with an extension field in a message.
//
// Variables of this type are generated in code by protoc-gen-go.
ExtensionDesc = protoimpl.ExtensionInfo
// ExtensionRange represents a range of message extensions.
// Used in code generated by protoc-gen-go.
ExtensionRange = protoiface.ExtensionRangeV1
// Deprecated: Do not use; this is an internal type.
Extension = protoimpl.ExtensionFieldV1
// Deprecated: Do not use; this is an internal type.
XXX_InternalExtensions = protoimpl.ExtensionFields
)
// ErrMissingExtension reports whether the extension was not present.
var ErrMissingExtension = errors.New("proto: missing extension")
var errNotExtendable = errors.New("proto: not an extendable proto.Message")
// HasExtension reports whether the extension field is present in m
// either as an explicitly populated field or as an unknown field.
func HasExtension(m Message, xt *ExtensionDesc) (has bool) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return false
}
// Check whether any populated known field matches the field number.
xtd := xt.TypeDescriptor()
if isValidExtension(mr.Descriptor(), xtd) {
has = mr.Has(xtd)
} else {
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
has = int32(fd.Number()) == xt.Field
return !has
})
}
// Check whether any unknown field matches the field number.
for b := mr.GetUnknown(); !has && len(b) > 0; {
num, _, n := protowire.ConsumeField(b)
has = int32(num) == xt.Field
b = b[n:]
}
return has
}
// ClearExtension removes the extension field from m
// either as an explicitly populated field or as an unknown field.
func ClearExtension(m Message, xt *ExtensionDesc) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return
}
xtd := xt.TypeDescriptor()
if isValidExtension(mr.Descriptor(), xtd) {
mr.Clear(xtd)
} else {
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
if int32(fd.Number()) == xt.Field {
mr.Clear(fd)
return false
}
return true
})
}
clearUnknown(mr, fieldNum(xt.Field))
}
// ClearAllExtensions clears all extensions from m.
// This includes populated fields and unknown fields in the extension range.
func ClearAllExtensions(m Message) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return
}
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
if fd.IsExtension() {
mr.Clear(fd)
}
return true
})
clearUnknown(mr, mr.Descriptor().ExtensionRanges())
}
// GetExtension retrieves a proto2 extended field from m.
//
// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
// then GetExtension parses the encoded field and returns a Go value of the specified type.
// If the field is not present, then the default value is returned (if one is specified),
// otherwise ErrMissingExtension is reported.
//
// If the descriptor is type incomplete (i.e., ExtensionDesc.ExtensionType is nil),
// then GetExtension returns the raw encoded bytes for the extension field.
func GetExtension(m Message, xt *ExtensionDesc) (interface{}, error) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
return nil, errNotExtendable
}
// Retrieve the unknown fields for this extension field.
var bo protoreflect.RawFields
for bi := mr.GetUnknown(); len(bi) > 0; {
num, _, n := protowire.ConsumeField(bi)
if int32(num) == xt.Field {
bo = append(bo, bi[:n]...)
}
bi = bi[n:]
}
// For type incomplete descriptors, only retrieve the unknown fields.
if xt.ExtensionType == nil {
return []byte(bo), nil
}
// If the extension field only exists as unknown fields, unmarshal it.
// This is rarely done since proto.Unmarshal eagerly unmarshals extensions.
xtd := xt.TypeDescriptor()
if !isValidExtension(mr.Descriptor(), xtd) {
return nil, fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
}
if !mr.Has(xtd) && len(bo) > 0 {
m2 := mr.New()
if err := (proto.UnmarshalOptions{
Resolver: extensionResolver{xt},
}.Unmarshal(bo, m2.Interface())); err != nil {
return nil, err
}
if m2.Has(xtd) {
mr.Set(xtd, m2.Get(xtd))
clearUnknown(mr, fieldNum(xt.Field))
}
}
// Check whether the message has the extension field set or a default.
var pv protoreflect.Value
switch {
case mr.Has(xtd):
pv = mr.Get(xtd)
case xtd.HasDefault():
pv = xtd.Default()
default:
return nil, ErrMissingExtension
}
v := xt.InterfaceOf(pv)
rv := reflect.ValueOf(v)
if isScalarKind(rv.Kind()) {
rv2 := reflect.New(rv.Type())
rv2.Elem().Set(rv)
v = rv2.Interface()
}
return v, nil
}
// extensionResolver is a custom extension resolver that stores a single
// extension type that takes precedence over the global registry.
type extensionResolver struct{ xt protoreflect.ExtensionType }
func (r extensionResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
if xtd := r.xt.TypeDescriptor(); xtd.FullName() == field {
return r.xt, nil
}
return protoregistry.GlobalTypes.FindExtensionByName(field)
}
func (r extensionResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
if xtd := r.xt.TypeDescriptor(); xtd.ContainingMessage().FullName() == message && xtd.Number() == field {
return r.xt, nil
}
return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
}
// GetExtensions returns a list of the extensions values present in m,
// corresponding with the provided list of extension descriptors, xts.
// If an extension is missing in m, the corresponding value is nil.
func GetExtensions(m Message, xts []*ExtensionDesc) ([]interface{}, error) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return nil, errNotExtendable
}
vs := make([]interface{}, len(xts))
for i, xt := range xts {
v, err := GetExtension(m, xt)
if err != nil {
if err == ErrMissingExtension {
continue
}
return vs, err
}
vs[i] = v
}
return vs, nil
}
// SetExtension sets an extension field in m to the provided value.
func SetExtension(m Message, xt *ExtensionDesc, v interface{}) error {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
return errNotExtendable
}
rv := reflect.ValueOf(v)
if reflect.TypeOf(v) != reflect.TypeOf(xt.ExtensionType) {
return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", v, xt.ExtensionType)
}
if rv.Kind() == reflect.Ptr {
if rv.IsNil() {
return fmt.Errorf("proto: SetExtension called with nil value of type %T", v)
}
if isScalarKind(rv.Elem().Kind()) {
v = rv.Elem().Interface()
}
}
xtd := xt.TypeDescriptor()
if !isValidExtension(mr.Descriptor(), xtd) {
return fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
}
mr.Set(xtd, xt.ValueOf(v))
clearUnknown(mr, fieldNum(xt.Field))
return nil
}
// SetRawExtension inserts b into the unknown fields of m.
//
// Deprecated: Use Message.ProtoReflect.SetUnknown instead.
func SetRawExtension(m Message, fnum int32, b []byte) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return
}
// Verify that the raw field is valid.
for b0 := b; len(b0) > 0; {
num, _, n := protowire.ConsumeField(b0)
if int32(num) != fnum {
panic(fmt.Sprintf("mismatching field number: got %d, want %d", num, fnum))
}
b0 = b0[n:]
}
ClearExtension(m, &ExtensionDesc{Field: fnum})
mr.SetUnknown(append(mr.GetUnknown(), b...))
}
// ExtensionDescs returns a list of extension descriptors found in m,
// containing descriptors for both populated extension fields in m and
// also unknown fields of m that are in the extension range.
// For the later case, an type incomplete descriptor is provided where only
// the ExtensionDesc.Field field is populated.
// The order of the extension descriptors is undefined.
func ExtensionDescs(m Message) ([]*ExtensionDesc, error) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
return nil, errNotExtendable
}
// Collect a set of known extension descriptors.
extDescs := make(map[protoreflect.FieldNumber]*ExtensionDesc)
mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
if fd.IsExtension() {
xt := fd.(protoreflect.ExtensionTypeDescriptor)
if xd, ok := xt.Type().(*ExtensionDesc); ok {
extDescs[fd.Number()] = xd
}
}
return true
})
// Collect a set of unknown extension descriptors.
extRanges := mr.Descriptor().ExtensionRanges()
for b := mr.GetUnknown(); len(b) > 0; {
num, _, n := protowire.ConsumeField(b)
if extRanges.Has(num) && extDescs[num] == nil {
extDescs[num] = nil
}
b = b[n:]
}
// Transpose the set of descriptors into a list.
var xts []*ExtensionDesc
for num, xt := range extDescs {
if xt == nil {
xt = &ExtensionDesc{Field: int32(num)}
}
xts = append(xts, xt)
}
return xts, nil
}
// isValidExtension reports whether xtd is a valid extension descriptor for md.
func isValidExtension(md protoreflect.MessageDescriptor, xtd protoreflect.ExtensionTypeDescriptor) bool {
return xtd.ContainingMessage() == md && md.ExtensionRanges().Has(xtd.Number())
}
// isScalarKind reports whether k is a protobuf scalar kind (except bytes).
// This function exists for historical reasons since the representation of
// scalars differs between v1 and v2, where v1 uses *T and v2 uses T.
func isScalarKind(k reflect.Kind) bool {
switch k {
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
return true
default:
return false
}
}
// clearUnknown removes unknown fields from m where remover.Has reports true.
func clearUnknown(m protoreflect.Message, remover interface {
Has(protoreflect.FieldNumber) bool
}) {
var bo protoreflect.RawFields
for bi := m.GetUnknown(); len(bi) > 0; {
num, _, n := protowire.ConsumeField(bi)
if !remover.Has(num) {
bo = append(bo, bi[:n]...)
}
bi = bi[n:]
}
if bi := m.GetUnknown(); len(bi) != len(bo) {
m.SetUnknown(bo)
}
}
type fieldNum protoreflect.FieldNumber
func (n1 fieldNum) Has(n2 protoreflect.FieldNumber) bool {
return protoreflect.FieldNumber(n1) == n2
}

306
vendor/github.com/golang/protobuf/proto/properties.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"fmt"
"reflect"
"strconv"
"strings"
"sync"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoimpl"
)
// StructProperties represents protocol buffer type information for a
// generated protobuf message in the open-struct API.
//
// Deprecated: Do not use.
type StructProperties struct {
// Prop are the properties for each field.
//
// Fields belonging to a oneof are stored in OneofTypes instead, with a
// single Properties representing the parent oneof held here.
//
// The order of Prop matches the order of fields in the Go struct.
// Struct fields that are not related to protobufs have a "XXX_" prefix
// in the Properties.Name and must be ignored by the user.
Prop []*Properties
// OneofTypes contains information about the oneof fields in this message.
// It is keyed by the protobuf field name.
OneofTypes map[string]*OneofProperties
}
// Properties represents the type information for a protobuf message field.
//
// Deprecated: Do not use.
type Properties struct {
// Name is a placeholder name with little meaningful semantic value.
// If the name has an "XXX_" prefix, the entire Properties must be ignored.
Name string
// OrigName is the protobuf field name or oneof name.
OrigName string
// JSONName is the JSON name for the protobuf field.
JSONName string
// Enum is a placeholder name for enums.
// For historical reasons, this is neither the Go name for the enum,
// nor the protobuf name for the enum.
Enum string // Deprecated: Do not use.
// Weak contains the full name of the weakly referenced message.
Weak string
// Wire is a string representation of the wire type.
Wire string
// WireType is the protobuf wire type for the field.
WireType int
// Tag is the protobuf field number.
Tag int
// Required reports whether this is a required field.
Required bool
// Optional reports whether this is a optional field.
Optional bool
// Repeated reports whether this is a repeated field.
Repeated bool
// Packed reports whether this is a packed repeated field of scalars.
Packed bool
// Proto3 reports whether this field operates under the proto3 syntax.
Proto3 bool
// Oneof reports whether this field belongs within a oneof.
Oneof bool
// Default is the default value in string form.
Default string
// HasDefault reports whether the field has a default value.
HasDefault bool
// MapKeyProp is the properties for the key field for a map field.
MapKeyProp *Properties
// MapValProp is the properties for the value field for a map field.
MapValProp *Properties
}
// OneofProperties represents the type information for a protobuf oneof.
//
// Deprecated: Do not use.
type OneofProperties struct {
// Type is a pointer to the generated wrapper type for the field value.
// This is nil for messages that are not in the open-struct API.
Type reflect.Type
// Field is the index into StructProperties.Prop for the containing oneof.
Field int
// Prop is the properties for the field.
Prop *Properties
}
// String formats the properties in the protobuf struct field tag style.
func (p *Properties) String() string {
s := p.Wire
s += "," + strconv.Itoa(p.Tag)
if p.Required {
s += ",req"
}
if p.Optional {
s += ",opt"
}
if p.Repeated {
s += ",rep"
}
if p.Packed {
s += ",packed"
}
s += ",name=" + p.OrigName
if p.JSONName != "" {
s += ",json=" + p.JSONName
}
if len(p.Enum) > 0 {
s += ",enum=" + p.Enum
}
if len(p.Weak) > 0 {
s += ",weak=" + p.Weak
}
if p.Proto3 {
s += ",proto3"
}
if p.Oneof {
s += ",oneof"
}
if p.HasDefault {
s += ",def=" + p.Default
}
return s
}
// Parse populates p by parsing a string in the protobuf struct field tag style.
func (p *Properties) Parse(tag string) {
// For example: "bytes,49,opt,name=foo,def=hello!"
for len(tag) > 0 {
i := strings.IndexByte(tag, ',')
if i < 0 {
i = len(tag)
}
switch s := tag[:i]; {
case strings.HasPrefix(s, "name="):
p.OrigName = s[len("name="):]
case strings.HasPrefix(s, "json="):
p.JSONName = s[len("json="):]
case strings.HasPrefix(s, "enum="):
p.Enum = s[len("enum="):]
case strings.HasPrefix(s, "weak="):
p.Weak = s[len("weak="):]
case strings.Trim(s, "0123456789") == "":
n, _ := strconv.ParseUint(s, 10, 32)
p.Tag = int(n)
case s == "opt":
p.Optional = true
case s == "req":
p.Required = true
case s == "rep":
p.Repeated = true
case s == "varint" || s == "zigzag32" || s == "zigzag64":
p.Wire = s
p.WireType = WireVarint
case s == "fixed32":
p.Wire = s
p.WireType = WireFixed32
case s == "fixed64":
p.Wire = s
p.WireType = WireFixed64
case s == "bytes":
p.Wire = s
p.WireType = WireBytes
case s == "group":
p.Wire = s
p.WireType = WireStartGroup
case s == "packed":
p.Packed = true
case s == "proto3":
p.Proto3 = true
case s == "oneof":
p.Oneof = true
case strings.HasPrefix(s, "def="):
// The default tag is special in that everything afterwards is the
// default regardless of the presence of commas.
p.HasDefault = true
p.Default, i = tag[len("def="):], len(tag)
}
tag = strings.TrimPrefix(tag[i:], ",")
}
}
// Init populates the properties from a protocol buffer struct tag.
//
// Deprecated: Do not use.
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
p.Name = name
p.OrigName = name
if tag == "" {
return
}
p.Parse(tag)
if typ != nil && typ.Kind() == reflect.Map {
p.MapKeyProp = new(Properties)
p.MapKeyProp.Init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
p.MapValProp = new(Properties)
p.MapValProp.Init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
}
}
var propertiesCache sync.Map // map[reflect.Type]*StructProperties
// GetProperties returns the list of properties for the type represented by t,
// which must be a generated protocol buffer message in the open-struct API,
// where protobuf message fields are represented by exported Go struct fields.
//
// Deprecated: Use protobuf reflection instead.
func GetProperties(t reflect.Type) *StructProperties {
if p, ok := propertiesCache.Load(t); ok {
return p.(*StructProperties)
}
p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
return p.(*StructProperties)
}
func newProperties(t reflect.Type) *StructProperties {
if t.Kind() != reflect.Struct {
panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
}
var hasOneof bool
prop := new(StructProperties)
// Construct a list of properties for each field in the struct.
for i := 0; i < t.NumField(); i++ {
p := new(Properties)
f := t.Field(i)
tagField := f.Tag.Get("protobuf")
p.Init(f.Type, f.Name, tagField, &f)
tagOneof := f.Tag.Get("protobuf_oneof")
if tagOneof != "" {
hasOneof = true
p.OrigName = tagOneof
}
// Rename unrelated struct fields with the "XXX_" prefix since so much
// user code simply checks for this to exclude special fields.
if tagField == "" && tagOneof == "" && !strings.HasPrefix(p.Name, "XXX_") {
p.Name = "XXX_" + p.Name
p.OrigName = "XXX_" + p.OrigName
} else if p.Weak != "" {
p.Name = p.OrigName // avoid possible "XXX_" prefix on weak field
}
prop.Prop = append(prop.Prop, p)
}
// Construct a mapping of oneof field names to properties.
if hasOneof {
var oneofWrappers []interface{}
if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
}
if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
}
if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoreflect.ProtoMessage); ok {
if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok {
oneofWrappers = m.ProtoMessageInfo().OneofWrappers
}
}
prop.OneofTypes = make(map[string]*OneofProperties)
for _, wrapper := range oneofWrappers {
p := &OneofProperties{
Type: reflect.ValueOf(wrapper).Type(), // *T
Prop: new(Properties),
}
f := p.Type.Elem().Field(0)
p.Prop.Name = f.Name
p.Prop.Parse(f.Tag.Get("protobuf"))
// Determine the struct field that contains this oneof.
// Each wrapper is assignable to exactly one parent field.
var foundOneof bool
for i := 0; i < t.NumField() && !foundOneof; i++ {
if p.Type.AssignableTo(t.Field(i).Type) {
p.Field = i
foundOneof = true
}
}
if !foundOneof {
panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
}
prop.OneofTypes[p.Prop.OrigName] = p
}
}
return prop
}
func (sp *StructProperties) Len() int { return len(sp.Prop) }
func (sp *StructProperties) Less(i, j int) bool { return false }
func (sp *StructProperties) Swap(i, j int) { return }

167
vendor/github.com/golang/protobuf/proto/proto.go generated vendored Normal file
View File

@ -0,0 +1,167 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package proto provides functionality for handling protocol buffer messages.
// In particular, it provides marshaling and unmarshaling between a protobuf
// message and the binary wire format.
//
// See https://developers.google.com/protocol-buffers/docs/gotutorial for
// more information.
//
// Deprecated: Use the "google.golang.org/protobuf/proto" package instead.
package proto
import (
protoV2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoiface"
"google.golang.org/protobuf/runtime/protoimpl"
)
const (
ProtoPackageIsVersion1 = true
ProtoPackageIsVersion2 = true
ProtoPackageIsVersion3 = true
ProtoPackageIsVersion4 = true
)
// GeneratedEnum is any enum type generated by protoc-gen-go
// which is a named int32 kind.
// This type exists for documentation purposes.
type GeneratedEnum interface{}
// GeneratedMessage is any message type generated by protoc-gen-go
// which is a pointer to a named struct kind.
// This type exists for documentation purposes.
type GeneratedMessage interface{}
// Message is a protocol buffer message.
//
// This is the v1 version of the message interface and is marginally better
// than an empty interface as it lacks any method to programatically interact
// with the contents of the message.
//
// A v2 message is declared in "google.golang.org/protobuf/proto".Message and
// exposes protobuf reflection as a first-class feature of the interface.
//
// To convert a v1 message to a v2 message, use the MessageV2 function.
// To convert a v2 message to a v1 message, use the MessageV1 function.
type Message = protoiface.MessageV1
// MessageV1 converts either a v1 or v2 message to a v1 message.
// It returns nil if m is nil.
func MessageV1(m GeneratedMessage) protoiface.MessageV1 {
return protoimpl.X.ProtoMessageV1Of(m)
}
// MessageV2 converts either a v1 or v2 message to a v2 message.
// It returns nil if m is nil.
func MessageV2(m GeneratedMessage) protoV2.Message {
return protoimpl.X.ProtoMessageV2Of(m)
}
// MessageReflect returns a reflective view for a message.
// It returns nil if m is nil.
func MessageReflect(m Message) protoreflect.Message {
return protoimpl.X.MessageOf(m)
}
// Marshaler is implemented by messages that can marshal themselves.
// This interface is used by the following functions: Size, Marshal,
// Buffer.Marshal, and Buffer.EncodeMessage.
//
// Deprecated: Do not implement.
type Marshaler interface {
// Marshal formats the encoded bytes of the message.
// It should be deterministic and emit valid protobuf wire data.
// The caller takes ownership of the returned buffer.
Marshal() ([]byte, error)
}
// Unmarshaler is implemented by messages that can unmarshal themselves.
// This interface is used by the following functions: Unmarshal, UnmarshalMerge,
// Buffer.Unmarshal, Buffer.DecodeMessage, and Buffer.DecodeGroup.
//
// Deprecated: Do not implement.
type Unmarshaler interface {
// Unmarshal parses the encoded bytes of the protobuf wire input.
// The provided buffer is only valid for during method call.
// It should not reset the receiver message.
Unmarshal([]byte) error
}
// Merger is implemented by messages that can merge themselves.
// This interface is used by the following functions: Clone and Merge.
//
// Deprecated: Do not implement.
type Merger interface {
// Merge merges the contents of src into the receiver message.
// It clones all data structures in src such that it aliases no mutable
// memory referenced by src.
Merge(src Message)
}
// RequiredNotSetError is an error type returned when
// marshaling or unmarshaling a message with missing required fields.
type RequiredNotSetError struct {
err error
}
func (e *RequiredNotSetError) Error() string {
if e.err != nil {
return e.err.Error()
}
return "proto: required field not set"
}
func (e *RequiredNotSetError) RequiredNotSet() bool {
return true
}
func checkRequiredNotSet(m protoV2.Message) error {
if err := protoV2.CheckInitialized(m); err != nil {
return &RequiredNotSetError{err: err}
}
return nil
}
// Clone returns a deep copy of src.
func Clone(src Message) Message {
return MessageV1(protoV2.Clone(MessageV2(src)))
}
// Merge merges src into dst, which must be messages of the same type.
//
// Populated scalar fields in src are copied to dst, while populated
// singular messages in src are merged into dst by recursively calling Merge.
// The elements of every list field in src is appended to the corresponded
// list fields in dst. The entries of every map field in src is copied into
// the corresponding map field in dst, possibly replacing existing entries.
// The unknown fields of src are appended to the unknown fields of dst.
func Merge(dst, src Message) {
protoV2.Merge(MessageV2(dst), MessageV2(src))
}
// Equal reports whether two messages are equal.
// If two messages marshal to the same bytes under deterministic serialization,
// then Equal is guaranteed to report true.
//
// Two messages are equal if they are the same protobuf message type,
// have the same set of populated known and extension field values,
// and the same set of unknown fields values.
//
// Scalar values are compared with the equivalent of the == operator in Go,
// except bytes values which are compared using bytes.Equal and
// floating point values which specially treat NaNs as equal.
// Message values are compared by recursively calling Equal.
// Lists are equal if each element value is also equal.
// Maps are equal if they have the same set of keys, where the pair of values
// for each key is also equal.
func Equal(x, y Message) bool {
return protoV2.Equal(MessageV2(x), MessageV2(y))
}
func isMessageSet(md protoreflect.MessageDescriptor) bool {
ms, ok := md.(interface{ IsMessageSet() bool })
return ok && ms.IsMessageSet()
}

317
vendor/github.com/golang/protobuf/proto/registry.go generated vendored Normal file
View File

@ -0,0 +1,317 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"reflect"
"strings"
"sync"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/runtime/protoimpl"
)
// filePath is the path to the proto source file.
type filePath = string // e.g., "google/protobuf/descriptor.proto"
// fileDescGZIP is the compressed contents of the encoded FileDescriptorProto.
type fileDescGZIP = []byte
var fileCache sync.Map // map[filePath]fileDescGZIP
// RegisterFile is called from generated code to register the compressed
// FileDescriptorProto with the file path for a proto source file.
//
// Deprecated: Use protoregistry.GlobalFiles.RegisterFile instead.
func RegisterFile(s filePath, d fileDescGZIP) {
// Decompress the descriptor.
zr, err := gzip.NewReader(bytes.NewReader(d))
if err != nil {
panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
}
b, err := ioutil.ReadAll(zr)
if err != nil {
panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
}
// Construct a protoreflect.FileDescriptor from the raw descriptor.
// Note that DescBuilder.Build automatically registers the constructed
// file descriptor with the v2 registry.
protoimpl.DescBuilder{RawDescriptor: b}.Build()
// Locally cache the raw descriptor form for the file.
fileCache.Store(s, d)
}
// FileDescriptor returns the compressed FileDescriptorProto given the file path
// for a proto source file. It returns nil if not found.
//
// Deprecated: Use protoregistry.GlobalFiles.FindFileByPath instead.
func FileDescriptor(s filePath) fileDescGZIP {
if v, ok := fileCache.Load(s); ok {
return v.(fileDescGZIP)
}
// Find the descriptor in the v2 registry.
var b []byte
if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil {
b, _ = Marshal(protodesc.ToFileDescriptorProto(fd))
}
// Locally cache the raw descriptor form for the file.
if len(b) > 0 {
v, _ := fileCache.LoadOrStore(s, protoimpl.X.CompressGZIP(b))
return v.(fileDescGZIP)
}
return nil
}
// enumName is the name of an enum. For historical reasons, the enum name is
// neither the full Go name nor the full protobuf name of the enum.
// The name is the dot-separated combination of just the proto package that the
// enum is declared within followed by the Go type name of the generated enum.
type enumName = string // e.g., "my.proto.package.GoMessage_GoEnum"
// enumsByName maps enum values by name to their numeric counterpart.
type enumsByName = map[string]int32
// enumsByNumber maps enum values by number to their name counterpart.
type enumsByNumber = map[int32]string
var enumCache sync.Map // map[enumName]enumsByName
var numFilesCache sync.Map // map[protoreflect.FullName]int
// RegisterEnum is called from the generated code to register the mapping of
// enum value names to enum numbers for the enum identified by s.
//
// Deprecated: Use protoregistry.GlobalTypes.RegisterEnum instead.
func RegisterEnum(s enumName, _ enumsByNumber, m enumsByName) {
if _, ok := enumCache.Load(s); ok {
panic("proto: duplicate enum registered: " + s)
}
enumCache.Store(s, m)
// This does not forward registration to the v2 registry since this API
// lacks sufficient information to construct a complete v2 enum descriptor.
}
// EnumValueMap returns the mapping from enum value names to enum numbers for
// the enum of the given name. It returns nil if not found.
//
// Deprecated: Use protoregistry.GlobalTypes.FindEnumByName instead.
func EnumValueMap(s enumName) enumsByName {
if v, ok := enumCache.Load(s); ok {
return v.(enumsByName)
}
// Check whether the cache is stale. If the number of files in the current
// package differs, then it means that some enums may have been recently
// registered upstream that we do not know about.
var protoPkg protoreflect.FullName
if i := strings.LastIndexByte(s, '.'); i >= 0 {
protoPkg = protoreflect.FullName(s[:i])
}
v, _ := numFilesCache.Load(protoPkg)
numFiles, _ := v.(int)
if protoregistry.GlobalFiles.NumFilesByPackage(protoPkg) == numFiles {
return nil // cache is up-to-date; was not found earlier
}
// Update the enum cache for all enums declared in the given proto package.
numFiles = 0
protoregistry.GlobalFiles.RangeFilesByPackage(protoPkg, func(fd protoreflect.FileDescriptor) bool {
walkEnums(fd, func(ed protoreflect.EnumDescriptor) {
name := protoimpl.X.LegacyEnumName(ed)
if _, ok := enumCache.Load(name); !ok {
m := make(enumsByName)
evs := ed.Values()
for i := evs.Len() - 1; i >= 0; i-- {
ev := evs.Get(i)
m[string(ev.Name())] = int32(ev.Number())
}
enumCache.LoadOrStore(name, m)
}
})
numFiles++
return true
})
numFilesCache.Store(protoPkg, numFiles)
// Check cache again for enum map.
if v, ok := enumCache.Load(s); ok {
return v.(enumsByName)
}
return nil
}
// walkEnums recursively walks all enums declared in d.
func walkEnums(d interface {
Enums() protoreflect.EnumDescriptors
Messages() protoreflect.MessageDescriptors
}, f func(protoreflect.EnumDescriptor)) {
eds := d.Enums()
for i := eds.Len() - 1; i >= 0; i-- {
f(eds.Get(i))
}
mds := d.Messages()
for i := mds.Len() - 1; i >= 0; i-- {
walkEnums(mds.Get(i), f)
}
}
// messageName is the full name of protobuf message.
type messageName = string
var messageTypeCache sync.Map // map[messageName]reflect.Type
// RegisterType is called from generated code to register the message Go type
// for a message of the given name.
//
// Deprecated: Use protoregistry.GlobalTypes.RegisterMessage instead.
func RegisterType(m Message, s messageName) {
mt := protoimpl.X.LegacyMessageTypeOf(m, protoreflect.FullName(s))
if err := protoregistry.GlobalTypes.RegisterMessage(mt); err != nil {
panic(err)
}
messageTypeCache.Store(s, reflect.TypeOf(m))
}
// RegisterMapType is called from generated code to register the Go map type
// for a protobuf message representing a map entry.
//
// Deprecated: Do not use.
func RegisterMapType(m interface{}, s messageName) {
t := reflect.TypeOf(m)
if t.Kind() != reflect.Map {
panic(fmt.Sprintf("invalid map kind: %v", t))
}
if _, ok := messageTypeCache.Load(s); ok {
panic(fmt.Errorf("proto: duplicate proto message registered: %s", s))
}
messageTypeCache.Store(s, t)
}
// MessageType returns the message type for a named message.
// It returns nil if not found.
//
// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead.
func MessageType(s messageName) reflect.Type {
if v, ok := messageTypeCache.Load(s); ok {
return v.(reflect.Type)
}
// Derive the message type from the v2 registry.
var t reflect.Type
if mt, _ := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(s)); mt != nil {
t = messageGoType(mt)
}
// If we could not get a concrete type, it is possible that it is a
// pseudo-message for a map entry.
if t == nil {
d, _ := protoregistry.GlobalFiles.FindDescriptorByName(protoreflect.FullName(s))
if md, _ := d.(protoreflect.MessageDescriptor); md != nil && md.IsMapEntry() {
kt := goTypeForField(md.Fields().ByNumber(1))
vt := goTypeForField(md.Fields().ByNumber(2))
t = reflect.MapOf(kt, vt)
}
}
// Locally cache the message type for the given name.
if t != nil {
v, _ := messageTypeCache.LoadOrStore(s, t)
return v.(reflect.Type)
}
return nil
}
func goTypeForField(fd protoreflect.FieldDescriptor) reflect.Type {
switch k := fd.Kind(); k {
case protoreflect.EnumKind:
if et, _ := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName()); et != nil {
return enumGoType(et)
}
return reflect.TypeOf(protoreflect.EnumNumber(0))
case protoreflect.MessageKind, protoreflect.GroupKind:
if mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName()); mt != nil {
return messageGoType(mt)
}
return reflect.TypeOf((*protoreflect.Message)(nil)).Elem()
default:
return reflect.TypeOf(fd.Default().Interface())
}
}
func enumGoType(et protoreflect.EnumType) reflect.Type {
return reflect.TypeOf(et.New(0))
}
func messageGoType(mt protoreflect.MessageType) reflect.Type {
return reflect.TypeOf(MessageV1(mt.Zero().Interface()))
}
// MessageName returns the full protobuf name for the given message type.
//
// Deprecated: Use protoreflect.MessageDescriptor.FullName instead.
func MessageName(m Message) messageName {
if m == nil {
return ""
}
if m, ok := m.(interface{ XXX_MessageName() messageName }); ok {
return m.XXX_MessageName()
}
return messageName(protoimpl.X.MessageDescriptorOf(m).FullName())
}
// RegisterExtension is called from the generated code to register
// the extension descriptor.
//
// Deprecated: Use protoregistry.GlobalTypes.RegisterExtension instead.
func RegisterExtension(d *ExtensionDesc) {
if err := protoregistry.GlobalTypes.RegisterExtension(d); err != nil {
panic(err)
}
}
type extensionsByNumber = map[int32]*ExtensionDesc
var extensionCache sync.Map // map[messageName]extensionsByNumber
// RegisteredExtensions returns a map of the registered extensions for the
// provided protobuf message, indexed by the extension field number.
//
// Deprecated: Use protoregistry.GlobalTypes.RangeExtensionsByMessage instead.
func RegisteredExtensions(m Message) extensionsByNumber {
// Check whether the cache is stale. If the number of extensions for
// the given message differs, then it means that some extensions were
// recently registered upstream that we do not know about.
s := MessageName(m)
v, _ := extensionCache.Load(s)
xs, _ := v.(extensionsByNumber)
if protoregistry.GlobalTypes.NumExtensionsByMessage(protoreflect.FullName(s)) == len(xs) {
return xs // cache is up-to-date
}
// Cache is stale, re-compute the extensions map.
xs = make(extensionsByNumber)
protoregistry.GlobalTypes.RangeExtensionsByMessage(protoreflect.FullName(s), func(xt protoreflect.ExtensionType) bool {
if xd, ok := xt.(*ExtensionDesc); ok {
xs[int32(xt.TypeDescriptor().Number())] = xd
} else {
// TODO: This implies that the protoreflect.ExtensionType is a
// custom type not generated by protoc-gen-go. We could try and
// convert the type to an ExtensionDesc.
}
return true
})
extensionCache.Store(s, xs)
return xs
}

801
vendor/github.com/golang/protobuf/proto/text_decode.go generated vendored Normal file
View File

@ -0,0 +1,801 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"encoding"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"unicode/utf8"
"google.golang.org/protobuf/encoding/prototext"
protoV2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
const wrapTextUnmarshalV2 = false
// ParseError is returned by UnmarshalText.
type ParseError struct {
Message string
// Deprecated: Do not use.
Line, Offset int
}
func (e *ParseError) Error() string {
if wrapTextUnmarshalV2 {
return e.Message
}
if e.Line == 1 {
return fmt.Sprintf("line 1.%d: %v", e.Offset, e.Message)
}
return fmt.Sprintf("line %d: %v", e.Line, e.Message)
}
// UnmarshalText parses a proto text formatted string into m.
func UnmarshalText(s string, m Message) error {
if u, ok := m.(encoding.TextUnmarshaler); ok {
return u.UnmarshalText([]byte(s))
}
m.Reset()
mi := MessageV2(m)
if wrapTextUnmarshalV2 {
err := prototext.UnmarshalOptions{
AllowPartial: true,
}.Unmarshal([]byte(s), mi)
if err != nil {
return &ParseError{Message: err.Error()}
}
return checkRequiredNotSet(mi)
} else {
if err := newTextParser(s).unmarshalMessage(mi.ProtoReflect(), ""); err != nil {
return err
}
return checkRequiredNotSet(mi)
}
}
type textParser struct {
s string // remaining input
done bool // whether the parsing is finished (success or error)
backed bool // whether back() was called
offset, line int
cur token
}
type token struct {
value string
err *ParseError
line int // line number
offset int // byte number from start of input, not start of line
unquoted string // the unquoted version of value, if it was a quoted string
}
func newTextParser(s string) *textParser {
p := new(textParser)
p.s = s
p.line = 1
p.cur.line = 1
return p
}
func (p *textParser) unmarshalMessage(m protoreflect.Message, terminator string) (err error) {
md := m.Descriptor()
fds := md.Fields()
// A struct is a sequence of "name: value", terminated by one of
// '>' or '}', or the end of the input. A name may also be
// "[extension]" or "[type/url]".
//
// The whole struct can also be an expanded Any message, like:
// [type/url] < ... struct contents ... >
seen := make(map[protoreflect.FieldNumber]bool)
for {
tok := p.next()
if tok.err != nil {
return tok.err
}
if tok.value == terminator {
break
}
if tok.value == "[" {
if err := p.unmarshalExtensionOrAny(m, seen); err != nil {
return err
}
continue
}
// This is a normal, non-extension field.
name := protoreflect.Name(tok.value)
fd := fds.ByName(name)
switch {
case fd == nil:
gd := fds.ByName(protoreflect.Name(strings.ToLower(string(name))))
if gd != nil && gd.Kind() == protoreflect.GroupKind && gd.Message().Name() == name {
fd = gd
}
case fd.Kind() == protoreflect.GroupKind && fd.Message().Name() != name:
fd = nil
case fd.IsWeak() && fd.Message().IsPlaceholder():
fd = nil
}
if fd == nil {
typeName := string(md.FullName())
if m, ok := m.Interface().(Message); ok {
t := reflect.TypeOf(m)
if t.Kind() == reflect.Ptr {
typeName = t.Elem().String()
}
}
return p.errorf("unknown field name %q in %v", name, typeName)
}
if od := fd.ContainingOneof(); od != nil && m.WhichOneof(od) != nil {
return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, od.Name())
}
if fd.Cardinality() != protoreflect.Repeated && seen[fd.Number()] {
return p.errorf("non-repeated field %q was repeated", fd.Name())
}
seen[fd.Number()] = true
// Consume any colon.
if err := p.checkForColon(fd); err != nil {
return err
}
// Parse into the field.
v := m.Get(fd)
if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
v = m.Mutable(fd)
}
if v, err = p.unmarshalValue(v, fd); err != nil {
return err
}
m.Set(fd, v)
if err := p.consumeOptionalSeparator(); err != nil {
return err
}
}
return nil
}
func (p *textParser) unmarshalExtensionOrAny(m protoreflect.Message, seen map[protoreflect.FieldNumber]bool) error {
name, err := p.consumeExtensionOrAnyName()
if err != nil {
return err
}
// If it contains a slash, it's an Any type URL.
if slashIdx := strings.LastIndex(name, "/"); slashIdx >= 0 {
tok := p.next()
if tok.err != nil {
return tok.err
}
// consume an optional colon
if tok.value == ":" {
tok = p.next()
if tok.err != nil {
return tok.err
}
}
var terminator string
switch tok.value {
case "<":
terminator = ">"
case "{":
terminator = "}"
default:
return p.errorf("expected '{' or '<', found %q", tok.value)
}
mt, err := protoregistry.GlobalTypes.FindMessageByURL(name)
if err != nil {
return p.errorf("unrecognized message %q in google.protobuf.Any", name[slashIdx+len("/"):])
}
m2 := mt.New()
if err := p.unmarshalMessage(m2, terminator); err != nil {
return err
}
b, err := protoV2.Marshal(m2.Interface())
if err != nil {
return p.errorf("failed to marshal message of type %q: %v", name[slashIdx+len("/"):], err)
}
urlFD := m.Descriptor().Fields().ByName("type_url")
valFD := m.Descriptor().Fields().ByName("value")
if seen[urlFD.Number()] {
return p.errorf("Any message unpacked multiple times, or %q already set", urlFD.Name())
}
if seen[valFD.Number()] {
return p.errorf("Any message unpacked multiple times, or %q already set", valFD.Name())
}
m.Set(urlFD, protoreflect.ValueOfString(name))
m.Set(valFD, protoreflect.ValueOfBytes(b))
seen[urlFD.Number()] = true
seen[valFD.Number()] = true
return nil
}
xname := protoreflect.FullName(name)
xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
if xt == nil && isMessageSet(m.Descriptor()) {
xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
}
if xt == nil {
return p.errorf("unrecognized extension %q", name)
}
fd := xt.TypeDescriptor()
if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
return p.errorf("extension field %q does not extend message %q", name, m.Descriptor().FullName())
}
if err := p.checkForColon(fd); err != nil {
return err
}
v := m.Get(fd)
if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
v = m.Mutable(fd)
}
v, err = p.unmarshalValue(v, fd)
if err != nil {
return err
}
m.Set(fd, v)
return p.consumeOptionalSeparator()
}
func (p *textParser) unmarshalValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
tok := p.next()
if tok.err != nil {
return v, tok.err
}
if tok.value == "" {
return v, p.errorf("unexpected EOF")
}
switch {
case fd.IsList():
lv := v.List()
var err error
if tok.value == "[" {
// Repeated field with list notation, like [1,2,3].
for {
vv := lv.NewElement()
vv, err = p.unmarshalSingularValue(vv, fd)
if err != nil {
return v, err
}
lv.Append(vv)
tok := p.next()
if tok.err != nil {
return v, tok.err
}
if tok.value == "]" {
break
}
if tok.value != "," {
return v, p.errorf("Expected ']' or ',' found %q", tok.value)
}
}
return v, nil
}
// One value of the repeated field.
p.back()
vv := lv.NewElement()
vv, err = p.unmarshalSingularValue(vv, fd)
if err != nil {
return v, err
}
lv.Append(vv)
return v, nil
case fd.IsMap():
// The map entry should be this sequence of tokens:
// < key : KEY value : VALUE >
// However, implementations may omit key or value, and technically
// we should support them in any order.
var terminator string
switch tok.value {
case "<":
terminator = ">"
case "{":
terminator = "}"
default:
return v, p.errorf("expected '{' or '<', found %q", tok.value)
}
keyFD := fd.MapKey()
valFD := fd.MapValue()
mv := v.Map()
kv := keyFD.Default()
vv := mv.NewValue()
for {
tok := p.next()
if tok.err != nil {
return v, tok.err
}
if tok.value == terminator {
break
}
var err error
switch tok.value {
case "key":
if err := p.consumeToken(":"); err != nil {
return v, err
}
if kv, err = p.unmarshalSingularValue(kv, keyFD); err != nil {
return v, err
}
if err := p.consumeOptionalSeparator(); err != nil {
return v, err
}
case "value":
if err := p.checkForColon(valFD); err != nil {
return v, err
}
if vv, err = p.unmarshalSingularValue(vv, valFD); err != nil {
return v, err
}
if err := p.consumeOptionalSeparator(); err != nil {
return v, err
}
default:
p.back()
return v, p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value)
}
}
mv.Set(kv.MapKey(), vv)
return v, nil
default:
p.back()
return p.unmarshalSingularValue(v, fd)
}
}
func (p *textParser) unmarshalSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
tok := p.next()
if tok.err != nil {
return v, tok.err
}
if tok.value == "" {
return v, p.errorf("unexpected EOF")
}
switch fd.Kind() {
case protoreflect.BoolKind:
switch tok.value {
case "true", "1", "t", "True":
return protoreflect.ValueOfBool(true), nil
case "false", "0", "f", "False":
return protoreflect.ValueOfBool(false), nil
}
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
return protoreflect.ValueOfInt32(int32(x)), nil
}
// The C++ parser accepts large positive hex numbers that uses
// two's complement arithmetic to represent negative numbers.
// This feature is here for backwards compatibility with C++.
if strings.HasPrefix(tok.value, "0x") {
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
return protoreflect.ValueOfInt32(int32(-(int64(^x) + 1))), nil
}
}
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
return protoreflect.ValueOfInt64(int64(x)), nil
}
// The C++ parser accepts large positive hex numbers that uses
// two's complement arithmetic to represent negative numbers.
// This feature is here for backwards compatibility with C++.
if strings.HasPrefix(tok.value, "0x") {
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
return protoreflect.ValueOfInt64(int64(-(int64(^x) + 1))), nil
}
}
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
return protoreflect.ValueOfUint32(uint32(x)), nil
}
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
return protoreflect.ValueOfUint64(uint64(x)), nil
}
case protoreflect.FloatKind:
// Ignore 'f' for compatibility with output generated by C++,
// but don't remove 'f' when the value is "-inf" or "inf".
v := tok.value
if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
v = v[:len(v)-len("f")]
}
if x, err := strconv.ParseFloat(v, 32); err == nil {
return protoreflect.ValueOfFloat32(float32(x)), nil
}
case protoreflect.DoubleKind:
// Ignore 'f' for compatibility with output generated by C++,
// but don't remove 'f' when the value is "-inf" or "inf".
v := tok.value
if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
v = v[:len(v)-len("f")]
}
if x, err := strconv.ParseFloat(v, 64); err == nil {
return protoreflect.ValueOfFloat64(float64(x)), nil
}
case protoreflect.StringKind:
if isQuote(tok.value[0]) {
return protoreflect.ValueOfString(tok.unquoted), nil
}
case protoreflect.BytesKind:
if isQuote(tok.value[0]) {
return protoreflect.ValueOfBytes([]byte(tok.unquoted)), nil
}
case protoreflect.EnumKind:
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
return protoreflect.ValueOfEnum(protoreflect.EnumNumber(x)), nil
}
vd := fd.Enum().Values().ByName(protoreflect.Name(tok.value))
if vd != nil {
return protoreflect.ValueOfEnum(vd.Number()), nil
}
case protoreflect.MessageKind, protoreflect.GroupKind:
var terminator string
switch tok.value {
case "{":
terminator = "}"
case "<":
terminator = ">"
default:
return v, p.errorf("expected '{' or '<', found %q", tok.value)
}
err := p.unmarshalMessage(v.Message(), terminator)
return v, err
default:
panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
}
return v, p.errorf("invalid %v: %v", fd.Kind(), tok.value)
}
// Consume a ':' from the input stream (if the next token is a colon),
// returning an error if a colon is needed but not present.
func (p *textParser) checkForColon(fd protoreflect.FieldDescriptor) *ParseError {
tok := p.next()
if tok.err != nil {
return tok.err
}
if tok.value != ":" {
if fd.Message() == nil {
return p.errorf("expected ':', found %q", tok.value)
}
p.back()
}
return nil
}
// consumeExtensionOrAnyName consumes an extension name or an Any type URL and
// the following ']'. It returns the name or URL consumed.
func (p *textParser) consumeExtensionOrAnyName() (string, error) {
tok := p.next()
if tok.err != nil {
return "", tok.err
}
// If extension name or type url is quoted, it's a single token.
if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] {
name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0]))
if err != nil {
return "", err
}
return name, p.consumeToken("]")
}
// Consume everything up to "]"
var parts []string
for tok.value != "]" {
parts = append(parts, tok.value)
tok = p.next()
if tok.err != nil {
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
}
if p.done && tok.value != "]" {
return "", p.errorf("unclosed type_url or extension name")
}
}
return strings.Join(parts, ""), nil
}
// consumeOptionalSeparator consumes an optional semicolon or comma.
// It is used in unmarshalMessage to provide backward compatibility.
func (p *textParser) consumeOptionalSeparator() error {
tok := p.next()
if tok.err != nil {
return tok.err
}
if tok.value != ";" && tok.value != "," {
p.back()
}
return nil
}
func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
p.cur.err = pe
p.done = true
return pe
}
func (p *textParser) skipWhitespace() {
i := 0
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
if p.s[i] == '#' {
// comment; skip to end of line or input
for i < len(p.s) && p.s[i] != '\n' {
i++
}
if i == len(p.s) {
break
}
}
if p.s[i] == '\n' {
p.line++
}
i++
}
p.offset += i
p.s = p.s[i:len(p.s)]
if len(p.s) == 0 {
p.done = true
}
}
func (p *textParser) advance() {
// Skip whitespace
p.skipWhitespace()
if p.done {
return
}
// Start of non-whitespace
p.cur.err = nil
p.cur.offset, p.cur.line = p.offset, p.line
p.cur.unquoted = ""
switch p.s[0] {
case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/':
// Single symbol
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
case '"', '\'':
// Quoted string
i := 1
for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
if p.s[i] == '\\' && i+1 < len(p.s) {
// skip escaped char
i++
}
i++
}
if i >= len(p.s) || p.s[i] != p.s[0] {
p.errorf("unmatched quote")
return
}
unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
if err != nil {
p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err)
return
}
p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
p.cur.unquoted = unq
default:
i := 0
for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
i++
}
if i == 0 {
p.errorf("unexpected byte %#x", p.s[0])
return
}
p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
}
p.offset += len(p.cur.value)
}
// Back off the parser by one token. Can only be done between calls to next().
// It makes the next advance() a no-op.
func (p *textParser) back() { p.backed = true }
// Advances the parser and returns the new current token.
func (p *textParser) next() *token {
if p.backed || p.done {
p.backed = false
return &p.cur
}
p.advance()
if p.done {
p.cur.value = ""
} else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
// Look for multiple quoted strings separated by whitespace,
// and concatenate them.
cat := p.cur
for {
p.skipWhitespace()
if p.done || !isQuote(p.s[0]) {
break
}
p.advance()
if p.cur.err != nil {
return &p.cur
}
cat.value += " " + p.cur.value
cat.unquoted += p.cur.unquoted
}
p.done = false // parser may have seen EOF, but we want to return cat
p.cur = cat
}
return &p.cur
}
func (p *textParser) consumeToken(s string) error {
tok := p.next()
if tok.err != nil {
return tok.err
}
if tok.value != s {
p.back()
return p.errorf("expected %q, found %q", s, tok.value)
}
return nil
}
var errBadUTF8 = errors.New("proto: bad UTF-8")
func unquoteC(s string, quote rune) (string, error) {
// This is based on C++'s tokenizer.cc.
// Despite its name, this is *not* parsing C syntax.
// For instance, "\0" is an invalid quoted string.
// Avoid allocation in trivial cases.
simple := true
for _, r := range s {
if r == '\\' || r == quote {
simple = false
break
}
}
if simple {
return s, nil
}
buf := make([]byte, 0, 3*len(s)/2)
for len(s) > 0 {
r, n := utf8.DecodeRuneInString(s)
if r == utf8.RuneError && n == 1 {
return "", errBadUTF8
}
s = s[n:]
if r != '\\' {
if r < utf8.RuneSelf {
buf = append(buf, byte(r))
} else {
buf = append(buf, string(r)...)
}
continue
}
ch, tail, err := unescape(s)
if err != nil {
return "", err
}
buf = append(buf, ch...)
s = tail
}
return string(buf), nil
}
func unescape(s string) (ch string, tail string, err error) {
r, n := utf8.DecodeRuneInString(s)
if r == utf8.RuneError && n == 1 {
return "", "", errBadUTF8
}
s = s[n:]
switch r {
case 'a':
return "\a", s, nil
case 'b':
return "\b", s, nil
case 'f':
return "\f", s, nil
case 'n':
return "\n", s, nil
case 'r':
return "\r", s, nil
case 't':
return "\t", s, nil
case 'v':
return "\v", s, nil
case '?':
return "?", s, nil // trigraph workaround
case '\'', '"', '\\':
return string(r), s, nil
case '0', '1', '2', '3', '4', '5', '6', '7':
if len(s) < 2 {
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
}
ss := string(r) + s[:2]
s = s[2:]
i, err := strconv.ParseUint(ss, 8, 8)
if err != nil {
return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss)
}
return string([]byte{byte(i)}), s, nil
case 'x', 'X', 'u', 'U':
var n int
switch r {
case 'x', 'X':
n = 2
case 'u':
n = 4
case 'U':
n = 8
}
if len(s) < n {
return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n)
}
ss := s[:n]
s = s[n:]
i, err := strconv.ParseUint(ss, 16, 64)
if err != nil {
return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss)
}
if r == 'x' || r == 'X' {
return string([]byte{byte(i)}), s, nil
}
if i > utf8.MaxRune {
return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss)
}
return string(rune(i)), s, nil
}
return "", "", fmt.Errorf(`unknown escape \%c`, r)
}
func isIdentOrNumberChar(c byte) bool {
switch {
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
return true
case '0' <= c && c <= '9':
return true
}
switch c {
case '-', '+', '.', '_':
return true
}
return false
}
func isWhitespace(c byte) bool {
switch c {
case ' ', '\t', '\n', '\r':
return true
}
return false
}
func isQuote(c byte) bool {
switch c {
case '"', '\'':
return true
}
return false
}

560
vendor/github.com/golang/protobuf/proto/text_encode.go generated vendored Normal file
View File

@ -0,0 +1,560 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"bytes"
"encoding"
"fmt"
"io"
"math"
"sort"
"strings"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
const wrapTextMarshalV2 = false
// TextMarshaler is a configurable text format marshaler.
type TextMarshaler struct {
Compact bool // use compact text format (one line)
ExpandAny bool // expand google.protobuf.Any messages of known types
}
// Marshal writes the proto text format of m to w.
func (tm *TextMarshaler) Marshal(w io.Writer, m Message) error {
b, err := tm.marshal(m)
if len(b) > 0 {
if _, err := w.Write(b); err != nil {
return err
}
}
return err
}
// Text returns a proto text formatted string of m.
func (tm *TextMarshaler) Text(m Message) string {
b, _ := tm.marshal(m)
return string(b)
}
func (tm *TextMarshaler) marshal(m Message) ([]byte, error) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return []byte("<nil>"), nil
}
if wrapTextMarshalV2 {
if m, ok := m.(encoding.TextMarshaler); ok {
return m.MarshalText()
}
opts := prototext.MarshalOptions{
AllowPartial: true,
EmitUnknown: true,
}
if !tm.Compact {
opts.Indent = " "
}
if !tm.ExpandAny {
opts.Resolver = (*protoregistry.Types)(nil)
}
return opts.Marshal(mr.Interface())
} else {
w := &textWriter{
compact: tm.Compact,
expandAny: tm.ExpandAny,
complete: true,
}
if m, ok := m.(encoding.TextMarshaler); ok {
b, err := m.MarshalText()
if err != nil {
return nil, err
}
w.Write(b)
return w.buf, nil
}
err := w.writeMessage(mr)
return w.buf, err
}
}
var (
defaultTextMarshaler = TextMarshaler{}
compactTextMarshaler = TextMarshaler{Compact: true}
)
// MarshalText writes the proto text format of m to w.
func MarshalText(w io.Writer, m Message) error { return defaultTextMarshaler.Marshal(w, m) }
// MarshalTextString returns a proto text formatted string of m.
func MarshalTextString(m Message) string { return defaultTextMarshaler.Text(m) }
// CompactText writes the compact proto text format of m to w.
func CompactText(w io.Writer, m Message) error { return compactTextMarshaler.Marshal(w, m) }
// CompactTextString returns a compact proto text formatted string of m.
func CompactTextString(m Message) string { return compactTextMarshaler.Text(m) }
var (
newline = []byte("\n")
endBraceNewline = []byte("}\n")
posInf = []byte("inf")
negInf = []byte("-inf")
nan = []byte("nan")
)
// textWriter is an io.Writer that tracks its indentation level.
type textWriter struct {
compact bool // same as TextMarshaler.Compact
expandAny bool // same as TextMarshaler.ExpandAny
complete bool // whether the current position is a complete line
indent int // indentation level; never negative
buf []byte
}
func (w *textWriter) Write(p []byte) (n int, _ error) {
newlines := bytes.Count(p, newline)
if newlines == 0 {
if !w.compact && w.complete {
w.writeIndent()
}
w.buf = append(w.buf, p...)
w.complete = false
return len(p), nil
}
frags := bytes.SplitN(p, newline, newlines+1)
if w.compact {
for i, frag := range frags {
if i > 0 {
w.buf = append(w.buf, ' ')
n++
}
w.buf = append(w.buf, frag...)
n += len(frag)
}
return n, nil
}
for i, frag := range frags {
if w.complete {
w.writeIndent()
}
w.buf = append(w.buf, frag...)
n += len(frag)
if i+1 < len(frags) {
w.buf = append(w.buf, '\n')
n++
}
}
w.complete = len(frags[len(frags)-1]) == 0
return n, nil
}
func (w *textWriter) WriteByte(c byte) error {
if w.compact && c == '\n' {
c = ' '
}
if !w.compact && w.complete {
w.writeIndent()
}
w.buf = append(w.buf, c)
w.complete = c == '\n'
return nil
}
func (w *textWriter) writeName(fd protoreflect.FieldDescriptor) {
if !w.compact && w.complete {
w.writeIndent()
}
w.complete = false
if fd.Kind() != protoreflect.GroupKind {
w.buf = append(w.buf, fd.Name()...)
w.WriteByte(':')
} else {
// Use message type name for group field name.
w.buf = append(w.buf, fd.Message().Name()...)
}
if !w.compact {
w.WriteByte(' ')
}
}
func requiresQuotes(u string) bool {
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
for _, ch := range u {
switch {
case ch == '.' || ch == '/' || ch == '_':
continue
case '0' <= ch && ch <= '9':
continue
case 'A' <= ch && ch <= 'Z':
continue
case 'a' <= ch && ch <= 'z':
continue
default:
return true
}
}
return false
}
// writeProto3Any writes an expanded google.protobuf.Any message.
//
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
// required messages are not linked in).
//
// It returns (true, error) when sv was written in expanded format or an error
// was encountered.
func (w *textWriter) writeProto3Any(m protoreflect.Message) (bool, error) {
md := m.Descriptor()
fdURL := md.Fields().ByName("type_url")
fdVal := md.Fields().ByName("value")
url := m.Get(fdURL).String()
mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
if err != nil {
return false, nil
}
b := m.Get(fdVal).Bytes()
m2 := mt.New()
if err := proto.Unmarshal(b, m2.Interface()); err != nil {
return false, nil
}
w.Write([]byte("["))
if requiresQuotes(url) {
w.writeQuotedString(url)
} else {
w.Write([]byte(url))
}
if w.compact {
w.Write([]byte("]:<"))
} else {
w.Write([]byte("]: <\n"))
w.indent++
}
if err := w.writeMessage(m2); err != nil {
return true, err
}
if w.compact {
w.Write([]byte("> "))
} else {
w.indent--
w.Write([]byte(">\n"))
}
return true, nil
}
func (w *textWriter) writeMessage(m protoreflect.Message) error {
md := m.Descriptor()
if w.expandAny && md.FullName() == "google.protobuf.Any" {
if canExpand, err := w.writeProto3Any(m); canExpand {
return err
}
}
fds := md.Fields()
for i := 0; i < fds.Len(); {
fd := fds.Get(i)
if od := fd.ContainingOneof(); od != nil {
fd = m.WhichOneof(od)
i += od.Fields().Len()
} else {
i++
}
if fd == nil || !m.Has(fd) {
continue
}
switch {
case fd.IsList():
lv := m.Get(fd).List()
for j := 0; j < lv.Len(); j++ {
w.writeName(fd)
v := lv.Get(j)
if err := w.writeSingularValue(v, fd); err != nil {
return err
}
w.WriteByte('\n')
}
case fd.IsMap():
kfd := fd.MapKey()
vfd := fd.MapValue()
mv := m.Get(fd).Map()
type entry struct{ key, val protoreflect.Value }
var entries []entry
mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
entries = append(entries, entry{k.Value(), v})
return true
})
sort.Slice(entries, func(i, j int) bool {
switch kfd.Kind() {
case protoreflect.BoolKind:
return !entries[i].key.Bool() && entries[j].key.Bool()
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
return entries[i].key.Int() < entries[j].key.Int()
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
return entries[i].key.Uint() < entries[j].key.Uint()
case protoreflect.StringKind:
return entries[i].key.String() < entries[j].key.String()
default:
panic("invalid kind")
}
})
for _, entry := range entries {
w.writeName(fd)
w.WriteByte('<')
if !w.compact {
w.WriteByte('\n')
}
w.indent++
w.writeName(kfd)
if err := w.writeSingularValue(entry.key, kfd); err != nil {
return err
}
w.WriteByte('\n')
w.writeName(vfd)
if err := w.writeSingularValue(entry.val, vfd); err != nil {
return err
}
w.WriteByte('\n')
w.indent--
w.WriteByte('>')
w.WriteByte('\n')
}
default:
w.writeName(fd)
if err := w.writeSingularValue(m.Get(fd), fd); err != nil {
return err
}
w.WriteByte('\n')
}
}
if b := m.GetUnknown(); len(b) > 0 {
w.writeUnknownFields(b)
}
return w.writeExtensions(m)
}
func (w *textWriter) writeSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
switch fd.Kind() {
case protoreflect.FloatKind, protoreflect.DoubleKind:
switch vf := v.Float(); {
case math.IsInf(vf, +1):
w.Write(posInf)
case math.IsInf(vf, -1):
w.Write(negInf)
case math.IsNaN(vf):
w.Write(nan)
default:
fmt.Fprint(w, v.Interface())
}
case protoreflect.StringKind:
// NOTE: This does not validate UTF-8 for historical reasons.
w.writeQuotedString(string(v.String()))
case protoreflect.BytesKind:
w.writeQuotedString(string(v.Bytes()))
case protoreflect.MessageKind, protoreflect.GroupKind:
var bra, ket byte = '<', '>'
if fd.Kind() == protoreflect.GroupKind {
bra, ket = '{', '}'
}
w.WriteByte(bra)
if !w.compact {
w.WriteByte('\n')
}
w.indent++
m := v.Message()
if m2, ok := m.Interface().(encoding.TextMarshaler); ok {
b, err := m2.MarshalText()
if err != nil {
return err
}
w.Write(b)
} else {
w.writeMessage(m)
}
w.indent--
w.WriteByte(ket)
case protoreflect.EnumKind:
if ev := fd.Enum().Values().ByNumber(v.Enum()); ev != nil {
fmt.Fprint(w, ev.Name())
} else {
fmt.Fprint(w, v.Enum())
}
default:
fmt.Fprint(w, v.Interface())
}
return nil
}
// writeQuotedString writes a quoted string in the protocol buffer text format.
func (w *textWriter) writeQuotedString(s string) {
w.WriteByte('"')
for i := 0; i < len(s); i++ {
switch c := s[i]; c {
case '\n':
w.buf = append(w.buf, `\n`...)
case '\r':
w.buf = append(w.buf, `\r`...)
case '\t':
w.buf = append(w.buf, `\t`...)
case '"':
w.buf = append(w.buf, `\"`...)
case '\\':
w.buf = append(w.buf, `\\`...)
default:
if isPrint := c >= 0x20 && c < 0x7f; isPrint {
w.buf = append(w.buf, c)
} else {
w.buf = append(w.buf, fmt.Sprintf(`\%03o`, c)...)
}
}
}
w.WriteByte('"')
}
func (w *textWriter) writeUnknownFields(b []byte) {
if !w.compact {
fmt.Fprintf(w, "/* %d unknown bytes */\n", len(b))
}
for len(b) > 0 {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return
}
b = b[n:]
if wtyp == protowire.EndGroupType {
w.indent--
w.Write(endBraceNewline)
continue
}
fmt.Fprint(w, num)
if wtyp != protowire.StartGroupType {
w.WriteByte(':')
}
if !w.compact || wtyp == protowire.StartGroupType {
w.WriteByte(' ')
}
switch wtyp {
case protowire.VarintType:
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return
}
b = b[n:]
fmt.Fprint(w, v)
case protowire.Fixed32Type:
v, n := protowire.ConsumeFixed32(b)
if n < 0 {
return
}
b = b[n:]
fmt.Fprint(w, v)
case protowire.Fixed64Type:
v, n := protowire.ConsumeFixed64(b)
if n < 0 {
return
}
b = b[n:]
fmt.Fprint(w, v)
case protowire.BytesType:
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return
}
b = b[n:]
fmt.Fprintf(w, "%q", v)
case protowire.StartGroupType:
w.WriteByte('{')
w.indent++
default:
fmt.Fprintf(w, "/* unknown wire type %d */", wtyp)
}
w.WriteByte('\n')
}
}
// writeExtensions writes all the extensions in m.
func (w *textWriter) writeExtensions(m protoreflect.Message) error {
md := m.Descriptor()
if md.ExtensionRanges().Len() == 0 {
return nil
}
type ext struct {
desc protoreflect.FieldDescriptor
val protoreflect.Value
}
var exts []ext
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
if fd.IsExtension() {
exts = append(exts, ext{fd, v})
}
return true
})
sort.Slice(exts, func(i, j int) bool {
return exts[i].desc.Number() < exts[j].desc.Number()
})
for _, ext := range exts {
// For message set, use the name of the message as the extension name.
name := string(ext.desc.FullName())
if isMessageSet(ext.desc.ContainingMessage()) {
name = strings.TrimSuffix(name, ".message_set_extension")
}
if !ext.desc.IsList() {
if err := w.writeSingularExtension(name, ext.val, ext.desc); err != nil {
return err
}
} else {
lv := ext.val.List()
for i := 0; i < lv.Len(); i++ {
if err := w.writeSingularExtension(name, lv.Get(i), ext.desc); err != nil {
return err
}
}
}
}
return nil
}
func (w *textWriter) writeSingularExtension(name string, v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
fmt.Fprintf(w, "[%s]:", name)
if !w.compact {
w.WriteByte(' ')
}
if err := w.writeSingularValue(v, fd); err != nil {
return err
}
w.WriteByte('\n')
return nil
}
func (w *textWriter) writeIndent() {
if !w.complete {
return
}
for i := 0; i < w.indent*2; i++ {
w.buf = append(w.buf, ' ')
}
w.complete = false
}

78
vendor/github.com/golang/protobuf/proto/wire.go generated vendored Normal file
View File

@ -0,0 +1,78 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
protoV2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/runtime/protoiface"
)
// Size returns the size in bytes of the wire-format encoding of m.
func Size(m Message) int {
if m == nil {
return 0
}
mi := MessageV2(m)
return protoV2.Size(mi)
}
// Marshal returns the wire-format encoding of m.
func Marshal(m Message) ([]byte, error) {
b, err := marshalAppend(nil, m, false)
if b == nil {
b = zeroBytes
}
return b, err
}
var zeroBytes = make([]byte, 0, 0)
func marshalAppend(buf []byte, m Message, deterministic bool) ([]byte, error) {
if m == nil {
return nil, ErrNil
}
mi := MessageV2(m)
nbuf, err := protoV2.MarshalOptions{
Deterministic: deterministic,
AllowPartial: true,
}.MarshalAppend(buf, mi)
if err != nil {
return buf, err
}
if len(buf) == len(nbuf) {
if !mi.ProtoReflect().IsValid() {
return buf, ErrNil
}
}
return nbuf, checkRequiredNotSet(mi)
}
// Unmarshal parses a wire-format message in b and places the decoded results in m.
//
// Unmarshal resets m before starting to unmarshal, so any existing data in m is always
// removed. Use UnmarshalMerge to preserve and append to existing data.
func Unmarshal(b []byte, m Message) error {
m.Reset()
return UnmarshalMerge(b, m)
}
// UnmarshalMerge parses a wire-format message in b and places the decoded results in m.
func UnmarshalMerge(b []byte, m Message) error {
mi := MessageV2(m)
out, err := protoV2.UnmarshalOptions{
AllowPartial: true,
Merge: true,
}.UnmarshalState(protoiface.UnmarshalInput{
Buf: b,
Message: mi.ProtoReflect(),
})
if err != nil {
return err
}
if out.Flags&protoiface.UnmarshalInitialized > 0 {
return nil
}
return checkRequiredNotSet(mi)
}

34
vendor/github.com/golang/protobuf/proto/wrappers.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
// Bool stores v in a new bool value and returns a pointer to it.
func Bool(v bool) *bool { return &v }
// Int stores v in a new int32 value and returns a pointer to it.
//
// Deprecated: Use Int32 instead.
func Int(v int) *int32 { return Int32(int32(v)) }
// Int32 stores v in a new int32 value and returns a pointer to it.
func Int32(v int32) *int32 { return &v }
// Int64 stores v in a new int64 value and returns a pointer to it.
func Int64(v int64) *int64 { return &v }
// Uint32 stores v in a new uint32 value and returns a pointer to it.
func Uint32(v uint32) *uint32 { return &v }
// Uint64 stores v in a new uint64 value and returns a pointer to it.
func Uint64(v uint64) *uint64 { return &v }
// Float32 stores v in a new float32 value and returns a pointer to it.
func Float32(v float32) *float32 { return &v }
// Float64 stores v in a new float64 value and returns a pointer to it.
func Float64(v float64) *float64 { return &v }
// String stores v in a new string value and returns a pointer to it.
func String(v string) *string { return &v }

View File

@ -744,6 +744,9 @@ func (d decoder) skipValue() error {
// Skip items. This will not validate whether skipped values are
// of the same type or not, same behavior as C++
// TextFormat::Parser::AllowUnknownField(true) version 3.8.0.
if err := d.skipValue(); err != nil {
return err
}
}
}
}

View File

@ -263,8 +263,3 @@ func (e *Encoder) Snapshot() encoderState {
func (e *Encoder) Reset(es encoderState) {
e.encoderState = es
}
// AppendString appends the escaped form of the input string to b.
func AppendString(b []byte, s string) []byte {
return appendString(b, s, false)
}

View File

@ -440,13 +440,6 @@ func legacyMerge(in piface.MergeInput) piface.MergeOutput {
if !ok {
return piface.MergeOutput{}
}
if !in.Source.IsValid() {
// Legacy Marshal methods may not function on nil messages.
// Check for a typed nil source only after we confirm that
// legacy Marshal/Unmarshal methods are present, for
// consistency.
return piface.MergeOutput{Flags: piface.MergeComplete}
}
b, err := marshaler.Marshal()
if err != nil {
return piface.MergeOutput{}

View File

@ -52,8 +52,8 @@ import (
// 10. Send out the CL for review and submit it.
const (
Major = 1
Minor = 27
Patch = 1
Minor = 26
Patch = 0
PreRelease = ""
)

View File

@ -0,0 +1,276 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package protodesc provides functionality for converting
// FileDescriptorProto messages to/from protoreflect.FileDescriptor values.
//
// The google.protobuf.FileDescriptorProto is a protobuf message that describes
// the type information for a .proto file in a form that is easily serializable.
// The protoreflect.FileDescriptor is a more structured representation of
// the FileDescriptorProto message where references and remote dependencies
// can be directly followed.
package protodesc
import (
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
)
// Resolver is the resolver used by NewFile to resolve dependencies.
// The enums and messages provided must belong to some parent file,
// which is also registered.
//
// It is implemented by protoregistry.Files.
type Resolver interface {
FindFileByPath(string) (protoreflect.FileDescriptor, error)
FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
}
// FileOptions configures the construction of file descriptors.
type FileOptions struct {
pragma.NoUnkeyedLiterals
// AllowUnresolvable configures New to permissively allow unresolvable
// file, enum, or message dependencies. Unresolved dependencies are replaced
// by placeholder equivalents.
//
// The following dependencies may be left unresolved:
// • Resolving an imported file.
// • Resolving the type for a message field or extension field.
// If the kind of the field is unknown, then a placeholder is used for both
// the Enum and Message accessors on the protoreflect.FieldDescriptor.
// • Resolving an enum value set as the default for an optional enum field.
// If unresolvable, the protoreflect.FieldDescriptor.Default is set to the
// first value in the associated enum (or zero if the also enum dependency
// is also unresolvable). The protoreflect.FieldDescriptor.DefaultEnumValue
// is populated with a placeholder.
// • Resolving the extended message type for an extension field.
// • Resolving the input or output message type for a service method.
//
// If the unresolved dependency uses a relative name,
// then the placeholder will contain an invalid FullName with a "*." prefix,
// indicating that the starting prefix of the full name is unknown.
AllowUnresolvable bool
}
// NewFile creates a new protoreflect.FileDescriptor from the provided
// file descriptor message. See FileOptions.New for more information.
func NewFile(fd *descriptorpb.FileDescriptorProto, r Resolver) (protoreflect.FileDescriptor, error) {
return FileOptions{}.New(fd, r)
}
// NewFiles creates a new protoregistry.Files from the provided
// FileDescriptorSet message. See FileOptions.NewFiles for more information.
func NewFiles(fd *descriptorpb.FileDescriptorSet) (*protoregistry.Files, error) {
return FileOptions{}.NewFiles(fd)
}
// New creates a new protoreflect.FileDescriptor from the provided
// file descriptor message. The file must represent a valid proto file according
// to protobuf semantics. The returned descriptor is a deep copy of the input.
//
// Any imported files, enum types, or message types referenced in the file are
// resolved using the provided registry. When looking up an import file path,
// the path must be unique. The newly created file descriptor is not registered
// back into the provided file registry.
func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (protoreflect.FileDescriptor, error) {
if r == nil {
r = (*protoregistry.Files)(nil) // empty resolver
}
// Handle the file descriptor content.
f := &filedesc.File{L2: &filedesc.FileL2{}}
switch fd.GetSyntax() {
case "proto2", "":
f.L1.Syntax = protoreflect.Proto2
case "proto3":
f.L1.Syntax = protoreflect.Proto3
default:
return nil, errors.New("invalid syntax: %q", fd.GetSyntax())
}
f.L1.Path = fd.GetName()
if f.L1.Path == "" {
return nil, errors.New("file path must be populated")
}
f.L1.Package = protoreflect.FullName(fd.GetPackage())
if !f.L1.Package.IsValid() && f.L1.Package != "" {
return nil, errors.New("invalid package: %q", f.L1.Package)
}
if opts := fd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.FileOptions)
f.L2.Options = func() protoreflect.ProtoMessage { return opts }
}
f.L2.Imports = make(filedesc.FileImports, len(fd.GetDependency()))
for _, i := range fd.GetPublicDependency() {
if !(0 <= i && int(i) < len(f.L2.Imports)) || f.L2.Imports[i].IsPublic {
return nil, errors.New("invalid or duplicate public import index: %d", i)
}
f.L2.Imports[i].IsPublic = true
}
for _, i := range fd.GetWeakDependency() {
if !(0 <= i && int(i) < len(f.L2.Imports)) || f.L2.Imports[i].IsWeak {
return nil, errors.New("invalid or duplicate weak import index: %d", i)
}
f.L2.Imports[i].IsWeak = true
}
imps := importSet{f.Path(): true}
for i, path := range fd.GetDependency() {
imp := &f.L2.Imports[i]
f, err := r.FindFileByPath(path)
if err == protoregistry.NotFound && (o.AllowUnresolvable || imp.IsWeak) {
f = filedesc.PlaceholderFile(path)
} else if err != nil {
return nil, errors.New("could not resolve import %q: %v", path, err)
}
imp.FileDescriptor = f
if imps[imp.Path()] {
return nil, errors.New("already imported %q", path)
}
imps[imp.Path()] = true
}
for i := range fd.GetDependency() {
imp := &f.L2.Imports[i]
imps.importPublic(imp.Imports())
}
// Handle source locations.
f.L2.Locations.File = f
for _, loc := range fd.GetSourceCodeInfo().GetLocation() {
var l protoreflect.SourceLocation
// TODO: Validate that the path points to an actual declaration?
l.Path = protoreflect.SourcePath(loc.GetPath())
s := loc.GetSpan()
switch len(s) {
case 3:
l.StartLine, l.StartColumn, l.EndLine, l.EndColumn = int(s[0]), int(s[1]), int(s[0]), int(s[2])
case 4:
l.StartLine, l.StartColumn, l.EndLine, l.EndColumn = int(s[0]), int(s[1]), int(s[2]), int(s[3])
default:
return nil, errors.New("invalid span: %v", s)
}
// TODO: Validate that the span information is sensible?
// See https://github.com/protocolbuffers/protobuf/issues/6378.
if false && (l.EndLine < l.StartLine || l.StartLine < 0 || l.StartColumn < 0 || l.EndColumn < 0 ||
(l.StartLine == l.EndLine && l.EndColumn <= l.StartColumn)) {
return nil, errors.New("invalid span: %v", s)
}
l.LeadingDetachedComments = loc.GetLeadingDetachedComments()
l.LeadingComments = loc.GetLeadingComments()
l.TrailingComments = loc.GetTrailingComments()
f.L2.Locations.List = append(f.L2.Locations.List, l)
}
// Step 1: Allocate and derive the names for all declarations.
// This copies all fields from the descriptor proto except:
// google.protobuf.FieldDescriptorProto.type_name
// google.protobuf.FieldDescriptorProto.default_value
// google.protobuf.FieldDescriptorProto.oneof_index
// google.protobuf.FieldDescriptorProto.extendee
// google.protobuf.MethodDescriptorProto.input
// google.protobuf.MethodDescriptorProto.output
var err error
sb := new(strs.Builder)
r1 := make(descsByName)
if f.L1.Enums.List, err = r1.initEnumDeclarations(fd.GetEnumType(), f, sb); err != nil {
return nil, err
}
if f.L1.Messages.List, err = r1.initMessagesDeclarations(fd.GetMessageType(), f, sb); err != nil {
return nil, err
}
if f.L1.Extensions.List, err = r1.initExtensionDeclarations(fd.GetExtension(), f, sb); err != nil {
return nil, err
}
if f.L1.Services.List, err = r1.initServiceDeclarations(fd.GetService(), f, sb); err != nil {
return nil, err
}
// Step 2: Resolve every dependency reference not handled by step 1.
r2 := &resolver{local: r1, remote: r, imports: imps, allowUnresolvable: o.AllowUnresolvable}
if err := r2.resolveMessageDependencies(f.L1.Messages.List, fd.GetMessageType()); err != nil {
return nil, err
}
if err := r2.resolveExtensionDependencies(f.L1.Extensions.List, fd.GetExtension()); err != nil {
return nil, err
}
if err := r2.resolveServiceDependencies(f.L1.Services.List, fd.GetService()); err != nil {
return nil, err
}
// Step 3: Validate every enum, message, and extension declaration.
if err := validateEnumDeclarations(f.L1.Enums.List, fd.GetEnumType()); err != nil {
return nil, err
}
if err := validateMessageDeclarations(f.L1.Messages.List, fd.GetMessageType()); err != nil {
return nil, err
}
if err := validateExtensionDeclarations(f.L1.Extensions.List, fd.GetExtension()); err != nil {
return nil, err
}
return f, nil
}
type importSet map[string]bool
func (is importSet) importPublic(imps protoreflect.FileImports) {
for i := 0; i < imps.Len(); i++ {
if imp := imps.Get(i); imp.IsPublic {
is[imp.Path()] = true
is.importPublic(imp.Imports())
}
}
}
// NewFiles creates a new protoregistry.Files from the provided
// FileDescriptorSet message. The descriptor set must include only
// valid files according to protobuf semantics. The returned descriptors
// are a deep copy of the input.
func (o FileOptions) NewFiles(fds *descriptorpb.FileDescriptorSet) (*protoregistry.Files, error) {
files := make(map[string]*descriptorpb.FileDescriptorProto)
for _, fd := range fds.File {
if _, ok := files[fd.GetName()]; ok {
return nil, errors.New("file appears multiple times: %q", fd.GetName())
}
files[fd.GetName()] = fd
}
r := &protoregistry.Files{}
for _, fd := range files {
if err := o.addFileDeps(r, fd, files); err != nil {
return nil, err
}
}
return r, nil
}
func (o FileOptions) addFileDeps(r *protoregistry.Files, fd *descriptorpb.FileDescriptorProto, files map[string]*descriptorpb.FileDescriptorProto) error {
// Set the entry to nil while descending into a file's dependencies to detect cycles.
files[fd.GetName()] = nil
for _, dep := range fd.Dependency {
depfd, ok := files[dep]
if depfd == nil {
if ok {
return errors.New("import cycle in file: %q", dep)
}
continue
}
if err := o.addFileDeps(r, depfd, files); err != nil {
return err
}
}
// Delete the entry once dependencies are processed.
delete(files, fd.GetName())
f, err := o.New(fd, r)
if err != nil {
return err
}
return r.RegisterFile(f)
}

View File

@ -0,0 +1,248 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package protodesc
import (
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)
type descsByName map[protoreflect.FullName]protoreflect.Descriptor
func (r descsByName) initEnumDeclarations(eds []*descriptorpb.EnumDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (es []filedesc.Enum, err error) {
es = make([]filedesc.Enum, len(eds)) // allocate up-front to ensure stable pointers
for i, ed := range eds {
e := &es[i]
e.L2 = new(filedesc.EnumL2)
if e.L0, err = r.makeBase(e, parent, ed.GetName(), i, sb); err != nil {
return nil, err
}
if opts := ed.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.EnumOptions)
e.L2.Options = func() protoreflect.ProtoMessage { return opts }
}
for _, s := range ed.GetReservedName() {
e.L2.ReservedNames.List = append(e.L2.ReservedNames.List, protoreflect.Name(s))
}
for _, rr := range ed.GetReservedRange() {
e.L2.ReservedRanges.List = append(e.L2.ReservedRanges.List, [2]protoreflect.EnumNumber{
protoreflect.EnumNumber(rr.GetStart()),
protoreflect.EnumNumber(rr.GetEnd()),
})
}
if e.L2.Values.List, err = r.initEnumValuesFromDescriptorProto(ed.GetValue(), e, sb); err != nil {
return nil, err
}
}
return es, nil
}
func (r descsByName) initEnumValuesFromDescriptorProto(vds []*descriptorpb.EnumValueDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (vs []filedesc.EnumValue, err error) {
vs = make([]filedesc.EnumValue, len(vds)) // allocate up-front to ensure stable pointers
for i, vd := range vds {
v := &vs[i]
if v.L0, err = r.makeBase(v, parent, vd.GetName(), i, sb); err != nil {
return nil, err
}
if opts := vd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.EnumValueOptions)
v.L1.Options = func() protoreflect.ProtoMessage { return opts }
}
v.L1.Number = protoreflect.EnumNumber(vd.GetNumber())
}
return vs, nil
}
func (r descsByName) initMessagesDeclarations(mds []*descriptorpb.DescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Message, err error) {
ms = make([]filedesc.Message, len(mds)) // allocate up-front to ensure stable pointers
for i, md := range mds {
m := &ms[i]
m.L2 = new(filedesc.MessageL2)
if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil {
return nil, err
}
if opts := md.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.MessageOptions)
m.L2.Options = func() protoreflect.ProtoMessage { return opts }
m.L1.IsMapEntry = opts.GetMapEntry()
m.L1.IsMessageSet = opts.GetMessageSetWireFormat()
}
for _, s := range md.GetReservedName() {
m.L2.ReservedNames.List = append(m.L2.ReservedNames.List, protoreflect.Name(s))
}
for _, rr := range md.GetReservedRange() {
m.L2.ReservedRanges.List = append(m.L2.ReservedRanges.List, [2]protoreflect.FieldNumber{
protoreflect.FieldNumber(rr.GetStart()),
protoreflect.FieldNumber(rr.GetEnd()),
})
}
for _, xr := range md.GetExtensionRange() {
m.L2.ExtensionRanges.List = append(m.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{
protoreflect.FieldNumber(xr.GetStart()),
protoreflect.FieldNumber(xr.GetEnd()),
})
var optsFunc func() protoreflect.ProtoMessage
if opts := xr.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.ExtensionRangeOptions)
optsFunc = func() protoreflect.ProtoMessage { return opts }
}
m.L2.ExtensionRangeOptions = append(m.L2.ExtensionRangeOptions, optsFunc)
}
if m.L2.Fields.List, err = r.initFieldsFromDescriptorProto(md.GetField(), m, sb); err != nil {
return nil, err
}
if m.L2.Oneofs.List, err = r.initOneofsFromDescriptorProto(md.GetOneofDecl(), m, sb); err != nil {
return nil, err
}
if m.L1.Enums.List, err = r.initEnumDeclarations(md.GetEnumType(), m, sb); err != nil {
return nil, err
}
if m.L1.Messages.List, err = r.initMessagesDeclarations(md.GetNestedType(), m, sb); err != nil {
return nil, err
}
if m.L1.Extensions.List, err = r.initExtensionDeclarations(md.GetExtension(), m, sb); err != nil {
return nil, err
}
}
return ms, nil
}
func (r descsByName) initFieldsFromDescriptorProto(fds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (fs []filedesc.Field, err error) {
fs = make([]filedesc.Field, len(fds)) // allocate up-front to ensure stable pointers
for i, fd := range fds {
f := &fs[i]
if f.L0, err = r.makeBase(f, parent, fd.GetName(), i, sb); err != nil {
return nil, err
}
f.L1.IsProto3Optional = fd.GetProto3Optional()
if opts := fd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
f.L1.Options = func() protoreflect.ProtoMessage { return opts }
f.L1.IsWeak = opts.GetWeak()
f.L1.HasPacked = opts.Packed != nil
f.L1.IsPacked = opts.GetPacked()
}
f.L1.Number = protoreflect.FieldNumber(fd.GetNumber())
f.L1.Cardinality = protoreflect.Cardinality(fd.GetLabel())
if fd.Type != nil {
f.L1.Kind = protoreflect.Kind(fd.GetType())
}
if fd.JsonName != nil {
f.L1.StringName.InitJSON(fd.GetJsonName())
}
}
return fs, nil
}
func (r descsByName) initOneofsFromDescriptorProto(ods []*descriptorpb.OneofDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (os []filedesc.Oneof, err error) {
os = make([]filedesc.Oneof, len(ods)) // allocate up-front to ensure stable pointers
for i, od := range ods {
o := &os[i]
if o.L0, err = r.makeBase(o, parent, od.GetName(), i, sb); err != nil {
return nil, err
}
if opts := od.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.OneofOptions)
o.L1.Options = func() protoreflect.ProtoMessage { return opts }
}
}
return os, nil
}
func (r descsByName) initExtensionDeclarations(xds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (xs []filedesc.Extension, err error) {
xs = make([]filedesc.Extension, len(xds)) // allocate up-front to ensure stable pointers
for i, xd := range xds {
x := &xs[i]
x.L2 = new(filedesc.ExtensionL2)
if x.L0, err = r.makeBase(x, parent, xd.GetName(), i, sb); err != nil {
return nil, err
}
if opts := xd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
x.L2.Options = func() protoreflect.ProtoMessage { return opts }
x.L2.IsPacked = opts.GetPacked()
}
x.L1.Number = protoreflect.FieldNumber(xd.GetNumber())
x.L1.Cardinality = protoreflect.Cardinality(xd.GetLabel())
if xd.Type != nil {
x.L1.Kind = protoreflect.Kind(xd.GetType())
}
if xd.JsonName != nil {
x.L2.StringName.InitJSON(xd.GetJsonName())
}
}
return xs, nil
}
func (r descsByName) initServiceDeclarations(sds []*descriptorpb.ServiceDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ss []filedesc.Service, err error) {
ss = make([]filedesc.Service, len(sds)) // allocate up-front to ensure stable pointers
for i, sd := range sds {
s := &ss[i]
s.L2 = new(filedesc.ServiceL2)
if s.L0, err = r.makeBase(s, parent, sd.GetName(), i, sb); err != nil {
return nil, err
}
if opts := sd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.ServiceOptions)
s.L2.Options = func() protoreflect.ProtoMessage { return opts }
}
if s.L2.Methods.List, err = r.initMethodsFromDescriptorProto(sd.GetMethod(), s, sb); err != nil {
return nil, err
}
}
return ss, nil
}
func (r descsByName) initMethodsFromDescriptorProto(mds []*descriptorpb.MethodDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Method, err error) {
ms = make([]filedesc.Method, len(mds)) // allocate up-front to ensure stable pointers
for i, md := range mds {
m := &ms[i]
if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil {
return nil, err
}
if opts := md.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.MethodOptions)
m.L1.Options = func() protoreflect.ProtoMessage { return opts }
}
m.L1.IsStreamingClient = md.GetClientStreaming()
m.L1.IsStreamingServer = md.GetServerStreaming()
}
return ms, nil
}
func (r descsByName) makeBase(child, parent protoreflect.Descriptor, name string, idx int, sb *strs.Builder) (filedesc.BaseL0, error) {
if !protoreflect.Name(name).IsValid() {
return filedesc.BaseL0{}, errors.New("descriptor %q has an invalid nested name: %q", parent.FullName(), name)
}
// Derive the full name of the child.
// Note that enum values are a sibling to the enum parent in the namespace.
var fullName protoreflect.FullName
if _, ok := parent.(protoreflect.EnumDescriptor); ok {
fullName = sb.AppendFullName(parent.FullName().Parent(), protoreflect.Name(name))
} else {
fullName = sb.AppendFullName(parent.FullName(), protoreflect.Name(name))
}
if _, ok := r[fullName]; ok {
return filedesc.BaseL0{}, errors.New("descriptor %q already declared", fullName)
}
r[fullName] = child
// TODO: Verify that the full name does not already exist in the resolver?
// This is not as critical since most usages of NewFile will register
// the created file back into the registry, which will perform this check.
return filedesc.BaseL0{
FullName: fullName,
ParentFile: parent.ParentFile().(*filedesc.File),
Parent: parent,
Index: idx,
}, nil
}

View File

@ -0,0 +1,286 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package protodesc
import (
"google.golang.org/protobuf/internal/encoding/defval"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
)
// resolver is a wrapper around a local registry of declarations within the file
// and the remote resolver. The remote resolver is restricted to only return
// descriptors that have been imported.
type resolver struct {
local descsByName
remote Resolver
imports importSet
allowUnresolvable bool
}
func (r *resolver) resolveMessageDependencies(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) (err error) {
for i, md := range mds {
m := &ms[i]
for j, fd := range md.GetField() {
f := &m.L2.Fields.List[j]
if f.L1.Cardinality == protoreflect.Required {
m.L2.RequiredNumbers.List = append(m.L2.RequiredNumbers.List, f.L1.Number)
}
if fd.OneofIndex != nil {
k := int(fd.GetOneofIndex())
if !(0 <= k && k < len(md.GetOneofDecl())) {
return errors.New("message field %q has an invalid oneof index: %d", f.FullName(), k)
}
o := &m.L2.Oneofs.List[k]
f.L1.ContainingOneof = o
o.L1.Fields.List = append(o.L1.Fields.List, f)
}
if f.L1.Kind, f.L1.Enum, f.L1.Message, err = r.findTarget(f.Kind(), f.Parent().FullName(), partialName(fd.GetTypeName()), f.IsWeak()); err != nil {
return errors.New("message field %q cannot resolve type: %v", f.FullName(), err)
}
if fd.DefaultValue != nil {
v, ev, err := unmarshalDefault(fd.GetDefaultValue(), f, r.allowUnresolvable)
if err != nil {
return errors.New("message field %q has invalid default: %v", f.FullName(), err)
}
f.L1.Default = filedesc.DefaultValue(v, ev)
}
}
if err := r.resolveMessageDependencies(m.L1.Messages.List, md.GetNestedType()); err != nil {
return err
}
if err := r.resolveExtensionDependencies(m.L1.Extensions.List, md.GetExtension()); err != nil {
return err
}
}
return nil
}
func (r *resolver) resolveExtensionDependencies(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) (err error) {
for i, xd := range xds {
x := &xs[i]
if x.L1.Extendee, err = r.findMessageDescriptor(x.Parent().FullName(), partialName(xd.GetExtendee()), false); err != nil {
return errors.New("extension field %q cannot resolve extendee: %v", x.FullName(), err)
}
if x.L1.Kind, x.L2.Enum, x.L2.Message, err = r.findTarget(x.Kind(), x.Parent().FullName(), partialName(xd.GetTypeName()), false); err != nil {
return errors.New("extension field %q cannot resolve type: %v", x.FullName(), err)
}
if xd.DefaultValue != nil {
v, ev, err := unmarshalDefault(xd.GetDefaultValue(), x, r.allowUnresolvable)
if err != nil {
return errors.New("extension field %q has invalid default: %v", x.FullName(), err)
}
x.L2.Default = filedesc.DefaultValue(v, ev)
}
}
return nil
}
func (r *resolver) resolveServiceDependencies(ss []filedesc.Service, sds []*descriptorpb.ServiceDescriptorProto) (err error) {
for i, sd := range sds {
s := &ss[i]
for j, md := range sd.GetMethod() {
m := &s.L2.Methods.List[j]
m.L1.Input, err = r.findMessageDescriptor(m.Parent().FullName(), partialName(md.GetInputType()), false)
if err != nil {
return errors.New("service method %q cannot resolve input: %v", m.FullName(), err)
}
m.L1.Output, err = r.findMessageDescriptor(s.FullName(), partialName(md.GetOutputType()), false)
if err != nil {
return errors.New("service method %q cannot resolve output: %v", m.FullName(), err)
}
}
}
return nil
}
// findTarget finds an enum or message descriptor if k is an enum, message,
// group, or unknown. If unknown, and the name could be resolved, the kind
// returned kind is set based on the type of the resolved descriptor.
func (r *resolver) findTarget(k protoreflect.Kind, scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.Kind, protoreflect.EnumDescriptor, protoreflect.MessageDescriptor, error) {
switch k {
case protoreflect.EnumKind:
ed, err := r.findEnumDescriptor(scope, ref, isWeak)
if err != nil {
return 0, nil, nil, err
}
return k, ed, nil, nil
case protoreflect.MessageKind, protoreflect.GroupKind:
md, err := r.findMessageDescriptor(scope, ref, isWeak)
if err != nil {
return 0, nil, nil, err
}
return k, nil, md, nil
case 0:
// Handle unspecified kinds (possible with parsers that operate
// on a per-file basis without knowledge of dependencies).
d, err := r.findDescriptor(scope, ref)
if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) {
return k, filedesc.PlaceholderEnum(ref.FullName()), filedesc.PlaceholderMessage(ref.FullName()), nil
} else if err == protoregistry.NotFound {
return 0, nil, nil, errors.New("%q not found", ref.FullName())
} else if err != nil {
return 0, nil, nil, err
}
switch d := d.(type) {
case protoreflect.EnumDescriptor:
return protoreflect.EnumKind, d, nil, nil
case protoreflect.MessageDescriptor:
return protoreflect.MessageKind, nil, d, nil
default:
return 0, nil, nil, errors.New("unknown kind")
}
default:
if ref != "" {
return 0, nil, nil, errors.New("target name cannot be specified for %v", k)
}
if !k.IsValid() {
return 0, nil, nil, errors.New("invalid kind: %d", k)
}
return k, nil, nil, nil
}
}
// findDescriptor finds the descriptor by name,
// which may be a relative name within some scope.
//
// Suppose the scope was "fizz.buzz" and the reference was "Foo.Bar",
// then the following full names are searched:
// * fizz.buzz.Foo.Bar
// * fizz.Foo.Bar
// * Foo.Bar
func (r *resolver) findDescriptor(scope protoreflect.FullName, ref partialName) (protoreflect.Descriptor, error) {
if !ref.IsValid() {
return nil, errors.New("invalid name reference: %q", ref)
}
if ref.IsFull() {
scope, ref = "", ref[1:]
}
var foundButNotImported protoreflect.Descriptor
for {
// Derive the full name to search.
s := protoreflect.FullName(ref)
if scope != "" {
s = scope + "." + s
}
// Check the current file for the descriptor.
if d, ok := r.local[s]; ok {
return d, nil
}
// Check the remote registry for the descriptor.
d, err := r.remote.FindDescriptorByName(s)
if err == nil {
// Only allow descriptors covered by one of the imports.
if r.imports[d.ParentFile().Path()] {
return d, nil
}
foundButNotImported = d
} else if err != protoregistry.NotFound {
return nil, errors.Wrap(err, "%q", s)
}
// Continue on at a higher level of scoping.
if scope == "" {
if d := foundButNotImported; d != nil {
return nil, errors.New("resolved %q, but %q is not imported", d.FullName(), d.ParentFile().Path())
}
return nil, protoregistry.NotFound
}
scope = scope.Parent()
}
}
func (r *resolver) findEnumDescriptor(scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.EnumDescriptor, error) {
d, err := r.findDescriptor(scope, ref)
if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) {
return filedesc.PlaceholderEnum(ref.FullName()), nil
} else if err == protoregistry.NotFound {
return nil, errors.New("%q not found", ref.FullName())
} else if err != nil {
return nil, err
}
ed, ok := d.(protoreflect.EnumDescriptor)
if !ok {
return nil, errors.New("resolved %q, but it is not an enum", d.FullName())
}
return ed, nil
}
func (r *resolver) findMessageDescriptor(scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.MessageDescriptor, error) {
d, err := r.findDescriptor(scope, ref)
if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) {
return filedesc.PlaceholderMessage(ref.FullName()), nil
} else if err == protoregistry.NotFound {
return nil, errors.New("%q not found", ref.FullName())
} else if err != nil {
return nil, err
}
md, ok := d.(protoreflect.MessageDescriptor)
if !ok {
return nil, errors.New("resolved %q, but it is not an message", d.FullName())
}
return md, nil
}
// partialName is the partial name. A leading dot means that the name is full,
// otherwise the name is relative to some current scope.
// See google.protobuf.FieldDescriptorProto.type_name.
type partialName string
func (s partialName) IsFull() bool {
return len(s) > 0 && s[0] == '.'
}
func (s partialName) IsValid() bool {
if s.IsFull() {
return protoreflect.FullName(s[1:]).IsValid()
}
return protoreflect.FullName(s).IsValid()
}
const unknownPrefix = "*."
// FullName converts the partial name to a full name on a best-effort basis.
// If relative, it creates an invalid full name, using a "*." prefix
// to indicate that the start of the full name is unknown.
func (s partialName) FullName() protoreflect.FullName {
if s.IsFull() {
return protoreflect.FullName(s[1:])
}
return protoreflect.FullName(unknownPrefix + s)
}
func unmarshalDefault(s string, fd protoreflect.FieldDescriptor, allowUnresolvable bool) (protoreflect.Value, protoreflect.EnumValueDescriptor, error) {
var evs protoreflect.EnumValueDescriptors
if fd.Enum() != nil {
evs = fd.Enum().Values()
}
v, ev, err := defval.Unmarshal(s, fd.Kind(), evs, defval.Descriptor)
if err != nil && allowUnresolvable && evs != nil && protoreflect.Name(s).IsValid() {
v = protoreflect.ValueOfEnum(0)
if evs.Len() > 0 {
v = protoreflect.ValueOfEnum(evs.Get(0).Number())
}
ev = filedesc.PlaceholderEnumValue(fd.Enum().FullName().Parent().Append(protoreflect.Name(s)))
} else if err != nil {
return v, ev, err
}
if fd.Syntax() == protoreflect.Proto3 {
return v, ev, errors.New("cannot be specified under proto3 semantics")
}
if fd.Kind() == protoreflect.MessageKind || fd.Kind() == protoreflect.GroupKind || fd.Cardinality() == protoreflect.Repeated {
return v, ev, errors.New("cannot be specified on composite types")
}
return v, ev, nil
}

View File

@ -0,0 +1,374 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package protodesc
import (
"strings"
"unicode"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/internal/filedesc"
"google.golang.org/protobuf/internal/flags"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)
func validateEnumDeclarations(es []filedesc.Enum, eds []*descriptorpb.EnumDescriptorProto) error {
for i, ed := range eds {
e := &es[i]
if err := e.L2.ReservedNames.CheckValid(); err != nil {
return errors.New("enum %q reserved names has %v", e.FullName(), err)
}
if err := e.L2.ReservedRanges.CheckValid(); err != nil {
return errors.New("enum %q reserved ranges has %v", e.FullName(), err)
}
if len(ed.GetValue()) == 0 {
return errors.New("enum %q must contain at least one value declaration", e.FullName())
}
allowAlias := ed.GetOptions().GetAllowAlias()
foundAlias := false
for i := 0; i < e.Values().Len(); i++ {
v1 := e.Values().Get(i)
if v2 := e.Values().ByNumber(v1.Number()); v1 != v2 {
foundAlias = true
if !allowAlias {
return errors.New("enum %q has conflicting non-aliased values on number %d: %q with %q", e.FullName(), v1.Number(), v1.Name(), v2.Name())
}
}
}
if allowAlias && !foundAlias {
return errors.New("enum %q allows aliases, but none were found", e.FullName())
}
if e.Syntax() == protoreflect.Proto3 {
if v := e.Values().Get(0); v.Number() != 0 {
return errors.New("enum %q using proto3 semantics must have zero number for the first value", v.FullName())
}
// Verify that value names in proto3 do not conflict if the
// case-insensitive prefix is removed.
// See protoc v3.8.0: src/google/protobuf/descriptor.cc:4991-5055
names := map[string]protoreflect.EnumValueDescriptor{}
prefix := strings.Replace(strings.ToLower(string(e.Name())), "_", "", -1)
for i := 0; i < e.Values().Len(); i++ {
v1 := e.Values().Get(i)
s := strs.EnumValueName(strs.TrimEnumPrefix(string(v1.Name()), prefix))
if v2, ok := names[s]; ok && v1.Number() != v2.Number() {
return errors.New("enum %q using proto3 semantics has conflict: %q with %q", e.FullName(), v1.Name(), v2.Name())
}
names[s] = v1
}
}
for j, vd := range ed.GetValue() {
v := &e.L2.Values.List[j]
if vd.Number == nil {
return errors.New("enum value %q must have a specified number", v.FullName())
}
if e.L2.ReservedNames.Has(v.Name()) {
return errors.New("enum value %q must not use reserved name", v.FullName())
}
if e.L2.ReservedRanges.Has(v.Number()) {
return errors.New("enum value %q must not use reserved number %d", v.FullName(), v.Number())
}
}
}
return nil
}
func validateMessageDeclarations(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) error {
for i, md := range mds {
m := &ms[i]
// Handle the message descriptor itself.
isMessageSet := md.GetOptions().GetMessageSetWireFormat()
if err := m.L2.ReservedNames.CheckValid(); err != nil {
return errors.New("message %q reserved names has %v", m.FullName(), err)
}
if err := m.L2.ReservedRanges.CheckValid(isMessageSet); err != nil {
return errors.New("message %q reserved ranges has %v", m.FullName(), err)
}
if err := m.L2.ExtensionRanges.CheckValid(isMessageSet); err != nil {
return errors.New("message %q extension ranges has %v", m.FullName(), err)
}
if err := (*filedesc.FieldRanges).CheckOverlap(&m.L2.ReservedRanges, &m.L2.ExtensionRanges); err != nil {
return errors.New("message %q reserved and extension ranges has %v", m.FullName(), err)
}
for i := 0; i < m.Fields().Len(); i++ {
f1 := m.Fields().Get(i)
if f2 := m.Fields().ByNumber(f1.Number()); f1 != f2 {
return errors.New("message %q has conflicting fields: %q with %q", m.FullName(), f1.Name(), f2.Name())
}
}
if isMessageSet && !flags.ProtoLegacy {
return errors.New("message %q is a MessageSet, which is a legacy proto1 feature that is no longer supported", m.FullName())
}
if isMessageSet && (m.Syntax() != protoreflect.Proto2 || m.Fields().Len() > 0 || m.ExtensionRanges().Len() == 0) {
return errors.New("message %q is an invalid proto1 MessageSet", m.FullName())
}
if m.Syntax() == protoreflect.Proto3 {
if m.ExtensionRanges().Len() > 0 {
return errors.New("message %q using proto3 semantics cannot have extension ranges", m.FullName())
}
// Verify that field names in proto3 do not conflict if lowercased
// with all underscores removed.
// See protoc v3.8.0: src/google/protobuf/descriptor.cc:5830-5847
names := map[string]protoreflect.FieldDescriptor{}
for i := 0; i < m.Fields().Len(); i++ {
f1 := m.Fields().Get(i)
s := strings.Replace(strings.ToLower(string(f1.Name())), "_", "", -1)
if f2, ok := names[s]; ok {
return errors.New("message %q using proto3 semantics has conflict: %q with %q", m.FullName(), f1.Name(), f2.Name())
}
names[s] = f1
}
}
for j, fd := range md.GetField() {
f := &m.L2.Fields.List[j]
if m.L2.ReservedNames.Has(f.Name()) {
return errors.New("message field %q must not use reserved name", f.FullName())
}
if !f.Number().IsValid() {
return errors.New("message field %q has an invalid number: %d", f.FullName(), f.Number())
}
if !f.Cardinality().IsValid() {
return errors.New("message field %q has an invalid cardinality: %d", f.FullName(), f.Cardinality())
}
if m.L2.ReservedRanges.Has(f.Number()) {
return errors.New("message field %q must not use reserved number %d", f.FullName(), f.Number())
}
if m.L2.ExtensionRanges.Has(f.Number()) {
return errors.New("message field %q with number %d in extension range", f.FullName(), f.Number())
}
if fd.Extendee != nil {
return errors.New("message field %q may not have extendee: %q", f.FullName(), fd.GetExtendee())
}
if f.L1.IsProto3Optional {
if f.Syntax() != protoreflect.Proto3 {
return errors.New("message field %q under proto3 optional semantics must be specified in the proto3 syntax", f.FullName())
}
if f.Cardinality() != protoreflect.Optional {
return errors.New("message field %q under proto3 optional semantics must have optional cardinality", f.FullName())
}
if f.ContainingOneof() != nil && f.ContainingOneof().Fields().Len() != 1 {
return errors.New("message field %q under proto3 optional semantics must be within a single element oneof", f.FullName())
}
}
if f.IsWeak() && !flags.ProtoLegacy {
return errors.New("message field %q is a weak field, which is a legacy proto1 feature that is no longer supported", f.FullName())
}
if f.IsWeak() && (f.Syntax() != protoreflect.Proto2 || !isOptionalMessage(f) || f.ContainingOneof() != nil) {
return errors.New("message field %q may only be weak for an optional message", f.FullName())
}
if f.IsPacked() && !isPackable(f) {
return errors.New("message field %q is not packable", f.FullName())
}
if err := checkValidGroup(f); err != nil {
return errors.New("message field %q is an invalid group: %v", f.FullName(), err)
}
if err := checkValidMap(f); err != nil {
return errors.New("message field %q is an invalid map: %v", f.FullName(), err)
}
if f.Syntax() == protoreflect.Proto3 {
if f.Cardinality() == protoreflect.Required {
return errors.New("message field %q using proto3 semantics cannot be required", f.FullName())
}
if f.Enum() != nil && !f.Enum().IsPlaceholder() && f.Enum().Syntax() != protoreflect.Proto3 {
return errors.New("message field %q using proto3 semantics may only depend on a proto3 enum", f.FullName())
}
}
}
seenSynthetic := false // synthetic oneofs for proto3 optional must come after real oneofs
for j := range md.GetOneofDecl() {
o := &m.L2.Oneofs.List[j]
if o.Fields().Len() == 0 {
return errors.New("message oneof %q must contain at least one field declaration", o.FullName())
}
if n := o.Fields().Len(); n-1 != (o.Fields().Get(n-1).Index() - o.Fields().Get(0).Index()) {
return errors.New("message oneof %q must have consecutively declared fields", o.FullName())
}
if o.IsSynthetic() {
seenSynthetic = true
continue
}
if !o.IsSynthetic() && seenSynthetic {
return errors.New("message oneof %q must be declared before synthetic oneofs", o.FullName())
}
for i := 0; i < o.Fields().Len(); i++ {
f := o.Fields().Get(i)
if f.Cardinality() != protoreflect.Optional {
return errors.New("message field %q belongs in a oneof and must be optional", f.FullName())
}
if f.IsWeak() {
return errors.New("message field %q belongs in a oneof and must not be a weak reference", f.FullName())
}
}
}
if err := validateEnumDeclarations(m.L1.Enums.List, md.GetEnumType()); err != nil {
return err
}
if err := validateMessageDeclarations(m.L1.Messages.List, md.GetNestedType()); err != nil {
return err
}
if err := validateExtensionDeclarations(m.L1.Extensions.List, md.GetExtension()); err != nil {
return err
}
}
return nil
}
func validateExtensionDeclarations(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) error {
for i, xd := range xds {
x := &xs[i]
// NOTE: Avoid using the IsValid method since extensions to MessageSet
// may have a field number higher than normal. This check only verifies
// that the number is not negative or reserved. We check again later
// if we know that the extendee is definitely not a MessageSet.
if n := x.Number(); n < 0 || (protowire.FirstReservedNumber <= n && n <= protowire.LastReservedNumber) {
return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
}
if !x.Cardinality().IsValid() || x.Cardinality() == protoreflect.Required {
return errors.New("extension field %q has an invalid cardinality: %d", x.FullName(), x.Cardinality())
}
if xd.JsonName != nil {
// A bug in older versions of protoc would always populate the
// "json_name" option for extensions when it is meaningless.
// When it did so, it would always use the camel-cased field name.
if xd.GetJsonName() != strs.JSONCamelCase(string(x.Name())) {
return errors.New("extension field %q may not have an explicitly set JSON name: %q", x.FullName(), xd.GetJsonName())
}
}
if xd.OneofIndex != nil {
return errors.New("extension field %q may not be part of a oneof", x.FullName())
}
if md := x.ContainingMessage(); !md.IsPlaceholder() {
if !md.ExtensionRanges().Has(x.Number()) {
return errors.New("extension field %q extends %q with non-extension field number: %d", x.FullName(), md.FullName(), x.Number())
}
isMessageSet := md.Options().(*descriptorpb.MessageOptions).GetMessageSetWireFormat()
if isMessageSet && !isOptionalMessage(x) {
return errors.New("extension field %q extends MessageSet and must be an optional message", x.FullName())
}
if !isMessageSet && !x.Number().IsValid() {
return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
}
}
if xd.GetOptions().GetWeak() {
return errors.New("extension field %q cannot be a weak reference", x.FullName())
}
if x.IsPacked() && !isPackable(x) {
return errors.New("extension field %q is not packable", x.FullName())
}
if err := checkValidGroup(x); err != nil {
return errors.New("extension field %q is an invalid group: %v", x.FullName(), err)
}
if md := x.Message(); md != nil && md.IsMapEntry() {
return errors.New("extension field %q cannot be a map entry", x.FullName())
}
if x.Syntax() == protoreflect.Proto3 {
switch x.ContainingMessage().FullName() {
case (*descriptorpb.FileOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.EnumOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.EnumValueOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.MessageOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.FieldOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.OneofOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.ExtensionRangeOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.ServiceOptions)(nil).ProtoReflect().Descriptor().FullName():
case (*descriptorpb.MethodOptions)(nil).ProtoReflect().Descriptor().FullName():
default:
return errors.New("extension field %q cannot be declared in proto3 unless extended descriptor options", x.FullName())
}
}
}
return nil
}
// isOptionalMessage reports whether this is an optional message.
// If the kind is unknown, it is assumed to be a message.
func isOptionalMessage(fd protoreflect.FieldDescriptor) bool {
return (fd.Kind() == 0 || fd.Kind() == protoreflect.MessageKind) && fd.Cardinality() == protoreflect.Optional
}
// isPackable checks whether the pack option can be specified.
func isPackable(fd protoreflect.FieldDescriptor) bool {
switch fd.Kind() {
case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
return false
}
return fd.IsList()
}
// checkValidGroup reports whether fd is a valid group according to the same
// rules that protoc imposes.
func checkValidGroup(fd protoreflect.FieldDescriptor) error {
md := fd.Message()
switch {
case fd.Kind() != protoreflect.GroupKind:
return nil
case fd.Syntax() != protoreflect.Proto2:
return errors.New("invalid under proto2 semantics")
case md == nil || md.IsPlaceholder():
return errors.New("message must be resolvable")
case fd.FullName().Parent() != md.FullName().Parent():
return errors.New("message and field must be declared in the same scope")
case !unicode.IsUpper(rune(md.Name()[0])):
return errors.New("message name must start with an uppercase")
case fd.Name() != protoreflect.Name(strings.ToLower(string(md.Name()))):
return errors.New("field name must be lowercased form of the message name")
}
return nil
}
// checkValidMap checks whether the field is a valid map according to the same
// rules that protoc imposes.
// See protoc v3.8.0: src/google/protobuf/descriptor.cc:6045-6115
func checkValidMap(fd protoreflect.FieldDescriptor) error {
md := fd.Message()
switch {
case md == nil || !md.IsMapEntry():
return nil
case fd.FullName().Parent() != md.FullName().Parent():
return errors.New("message and field must be declared in the same scope")
case md.Name() != protoreflect.Name(strs.MapEntryName(string(fd.Name()))):
return errors.New("incorrect implicit map entry name")
case fd.Cardinality() != protoreflect.Repeated:
return errors.New("field must be repeated")
case md.Fields().Len() != 2:
return errors.New("message must have exactly two fields")
case md.ExtensionRanges().Len() > 0:
return errors.New("message must not have any extension ranges")
case md.Enums().Len()+md.Messages().Len()+md.Extensions().Len() > 0:
return errors.New("message must not have any nested declarations")
}
kf := md.Fields().Get(0)
vf := md.Fields().Get(1)
switch {
case kf.Name() != genid.MapEntry_Key_field_name || kf.Number() != genid.MapEntry_Key_field_number || kf.Cardinality() != protoreflect.Optional || kf.ContainingOneof() != nil || kf.HasDefault():
return errors.New("invalid key field")
case vf.Name() != genid.MapEntry_Value_field_name || vf.Number() != genid.MapEntry_Value_field_number || vf.Cardinality() != protoreflect.Optional || vf.ContainingOneof() != nil || vf.HasDefault():
return errors.New("invalid value field")
}
switch kf.Kind() {
case protoreflect.BoolKind: // bool
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: // int32
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: // int64
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: // uint32
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: // uint64
case protoreflect.StringKind: // string
default:
return errors.New("invalid key kind: %v", kf.Kind())
}
if e := vf.Enum(); e != nil && e.Values().Len() > 0 && e.Values().Get(0).Number() != 0 {
return errors.New("map enum value must have zero number for the first value")
}
return nil
}

View File

@ -0,0 +1,252 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package protodesc
import (
"fmt"
"strings"
"google.golang.org/protobuf/internal/encoding/defval"
"google.golang.org/protobuf/internal/strs"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)
// ToFileDescriptorProto copies a protoreflect.FileDescriptor into a
// google.protobuf.FileDescriptorProto message.
func ToFileDescriptorProto(file protoreflect.FileDescriptor) *descriptorpb.FileDescriptorProto {
p := &descriptorpb.FileDescriptorProto{
Name: proto.String(file.Path()),
Options: proto.Clone(file.Options()).(*descriptorpb.FileOptions),
}
if file.Package() != "" {
p.Package = proto.String(string(file.Package()))
}
for i, imports := 0, file.Imports(); i < imports.Len(); i++ {
imp := imports.Get(i)
p.Dependency = append(p.Dependency, imp.Path())
if imp.IsPublic {
p.PublicDependency = append(p.PublicDependency, int32(i))
}
if imp.IsWeak {
p.WeakDependency = append(p.WeakDependency, int32(i))
}
}
for i, locs := 0, file.SourceLocations(); i < locs.Len(); i++ {
loc := locs.Get(i)
l := &descriptorpb.SourceCodeInfo_Location{}
l.Path = append(l.Path, loc.Path...)
if loc.StartLine == loc.EndLine {
l.Span = []int32{int32(loc.StartLine), int32(loc.StartColumn), int32(loc.EndColumn)}
} else {
l.Span = []int32{int32(loc.StartLine), int32(loc.StartColumn), int32(loc.EndLine), int32(loc.EndColumn)}
}
l.LeadingDetachedComments = append([]string(nil), loc.LeadingDetachedComments...)
if loc.LeadingComments != "" {
l.LeadingComments = proto.String(loc.LeadingComments)
}
if loc.TrailingComments != "" {
l.TrailingComments = proto.String(loc.TrailingComments)
}
if p.SourceCodeInfo == nil {
p.SourceCodeInfo = &descriptorpb.SourceCodeInfo{}
}
p.SourceCodeInfo.Location = append(p.SourceCodeInfo.Location, l)
}
for i, messages := 0, file.Messages(); i < messages.Len(); i++ {
p.MessageType = append(p.MessageType, ToDescriptorProto(messages.Get(i)))
}
for i, enums := 0, file.Enums(); i < enums.Len(); i++ {
p.EnumType = append(p.EnumType, ToEnumDescriptorProto(enums.Get(i)))
}
for i, services := 0, file.Services(); i < services.Len(); i++ {
p.Service = append(p.Service, ToServiceDescriptorProto(services.Get(i)))
}
for i, exts := 0, file.Extensions(); i < exts.Len(); i++ {
p.Extension = append(p.Extension, ToFieldDescriptorProto(exts.Get(i)))
}
if syntax := file.Syntax(); syntax != protoreflect.Proto2 {
p.Syntax = proto.String(file.Syntax().String())
}
return p
}
// ToDescriptorProto copies a protoreflect.MessageDescriptor into a
// google.protobuf.DescriptorProto message.
func ToDescriptorProto(message protoreflect.MessageDescriptor) *descriptorpb.DescriptorProto {
p := &descriptorpb.DescriptorProto{
Name: proto.String(string(message.Name())),
Options: proto.Clone(message.Options()).(*descriptorpb.MessageOptions),
}
for i, fields := 0, message.Fields(); i < fields.Len(); i++ {
p.Field = append(p.Field, ToFieldDescriptorProto(fields.Get(i)))
}
for i, exts := 0, message.Extensions(); i < exts.Len(); i++ {
p.Extension = append(p.Extension, ToFieldDescriptorProto(exts.Get(i)))
}
for i, messages := 0, message.Messages(); i < messages.Len(); i++ {
p.NestedType = append(p.NestedType, ToDescriptorProto(messages.Get(i)))
}
for i, enums := 0, message.Enums(); i < enums.Len(); i++ {
p.EnumType = append(p.EnumType, ToEnumDescriptorProto(enums.Get(i)))
}
for i, xranges := 0, message.ExtensionRanges(); i < xranges.Len(); i++ {
xrange := xranges.Get(i)
p.ExtensionRange = append(p.ExtensionRange, &descriptorpb.DescriptorProto_ExtensionRange{
Start: proto.Int32(int32(xrange[0])),
End: proto.Int32(int32(xrange[1])),
Options: proto.Clone(message.ExtensionRangeOptions(i)).(*descriptorpb.ExtensionRangeOptions),
})
}
for i, oneofs := 0, message.Oneofs(); i < oneofs.Len(); i++ {
p.OneofDecl = append(p.OneofDecl, ToOneofDescriptorProto(oneofs.Get(i)))
}
for i, ranges := 0, message.ReservedRanges(); i < ranges.Len(); i++ {
rrange := ranges.Get(i)
p.ReservedRange = append(p.ReservedRange, &descriptorpb.DescriptorProto_ReservedRange{
Start: proto.Int32(int32(rrange[0])),
End: proto.Int32(int32(rrange[1])),
})
}
for i, names := 0, message.ReservedNames(); i < names.Len(); i++ {
p.ReservedName = append(p.ReservedName, string(names.Get(i)))
}
return p
}
// ToFieldDescriptorProto copies a protoreflect.FieldDescriptor into a
// google.protobuf.FieldDescriptorProto message.
func ToFieldDescriptorProto(field protoreflect.FieldDescriptor) *descriptorpb.FieldDescriptorProto {
p := &descriptorpb.FieldDescriptorProto{
Name: proto.String(string(field.Name())),
Number: proto.Int32(int32(field.Number())),
Label: descriptorpb.FieldDescriptorProto_Label(field.Cardinality()).Enum(),
Options: proto.Clone(field.Options()).(*descriptorpb.FieldOptions),
}
if field.IsExtension() {
p.Extendee = fullNameOf(field.ContainingMessage())
}
if field.Kind().IsValid() {
p.Type = descriptorpb.FieldDescriptorProto_Type(field.Kind()).Enum()
}
if field.Enum() != nil {
p.TypeName = fullNameOf(field.Enum())
}
if field.Message() != nil {
p.TypeName = fullNameOf(field.Message())
}
if field.HasJSONName() {
// A bug in older versions of protoc would always populate the
// "json_name" option for extensions when it is meaningless.
// When it did so, it would always use the camel-cased field name.
if field.IsExtension() {
p.JsonName = proto.String(strs.JSONCamelCase(string(field.Name())))
} else {
p.JsonName = proto.String(field.JSONName())
}
}
if field.Syntax() == protoreflect.Proto3 && field.HasOptionalKeyword() {
p.Proto3Optional = proto.Bool(true)
}
if field.HasDefault() {
def, err := defval.Marshal(field.Default(), field.DefaultEnumValue(), field.Kind(), defval.Descriptor)
if err != nil && field.DefaultEnumValue() != nil {
def = string(field.DefaultEnumValue().Name()) // occurs for unresolved enum values
} else if err != nil {
panic(fmt.Sprintf("%v: %v", field.FullName(), err))
}
p.DefaultValue = proto.String(def)
}
if oneof := field.ContainingOneof(); oneof != nil {
p.OneofIndex = proto.Int32(int32(oneof.Index()))
}
return p
}
// ToOneofDescriptorProto copies a protoreflect.OneofDescriptor into a
// google.protobuf.OneofDescriptorProto message.
func ToOneofDescriptorProto(oneof protoreflect.OneofDescriptor) *descriptorpb.OneofDescriptorProto {
return &descriptorpb.OneofDescriptorProto{
Name: proto.String(string(oneof.Name())),
Options: proto.Clone(oneof.Options()).(*descriptorpb.OneofOptions),
}
}
// ToEnumDescriptorProto copies a protoreflect.EnumDescriptor into a
// google.protobuf.EnumDescriptorProto message.
func ToEnumDescriptorProto(enum protoreflect.EnumDescriptor) *descriptorpb.EnumDescriptorProto {
p := &descriptorpb.EnumDescriptorProto{
Name: proto.String(string(enum.Name())),
Options: proto.Clone(enum.Options()).(*descriptorpb.EnumOptions),
}
for i, values := 0, enum.Values(); i < values.Len(); i++ {
p.Value = append(p.Value, ToEnumValueDescriptorProto(values.Get(i)))
}
for i, ranges := 0, enum.ReservedRanges(); i < ranges.Len(); i++ {
rrange := ranges.Get(i)
p.ReservedRange = append(p.ReservedRange, &descriptorpb.EnumDescriptorProto_EnumReservedRange{
Start: proto.Int32(int32(rrange[0])),
End: proto.Int32(int32(rrange[1])),
})
}
for i, names := 0, enum.ReservedNames(); i < names.Len(); i++ {
p.ReservedName = append(p.ReservedName, string(names.Get(i)))
}
return p
}
// ToEnumValueDescriptorProto copies a protoreflect.EnumValueDescriptor into a
// google.protobuf.EnumValueDescriptorProto message.
func ToEnumValueDescriptorProto(value protoreflect.EnumValueDescriptor) *descriptorpb.EnumValueDescriptorProto {
return &descriptorpb.EnumValueDescriptorProto{
Name: proto.String(string(value.Name())),
Number: proto.Int32(int32(value.Number())),
Options: proto.Clone(value.Options()).(*descriptorpb.EnumValueOptions),
}
}
// ToServiceDescriptorProto copies a protoreflect.ServiceDescriptor into a
// google.protobuf.ServiceDescriptorProto message.
func ToServiceDescriptorProto(service protoreflect.ServiceDescriptor) *descriptorpb.ServiceDescriptorProto {
p := &descriptorpb.ServiceDescriptorProto{
Name: proto.String(string(service.Name())),
Options: proto.Clone(service.Options()).(*descriptorpb.ServiceOptions),
}
for i, methods := 0, service.Methods(); i < methods.Len(); i++ {
p.Method = append(p.Method, ToMethodDescriptorProto(methods.Get(i)))
}
return p
}
// ToMethodDescriptorProto copies a protoreflect.MethodDescriptor into a
// google.protobuf.MethodDescriptorProto message.
func ToMethodDescriptorProto(method protoreflect.MethodDescriptor) *descriptorpb.MethodDescriptorProto {
p := &descriptorpb.MethodDescriptorProto{
Name: proto.String(string(method.Name())),
InputType: fullNameOf(method.Input()),
OutputType: fullNameOf(method.Output()),
Options: proto.Clone(method.Options()).(*descriptorpb.MethodOptions),
}
if method.IsStreamingClient() {
p.ClientStreaming = proto.Bool(true)
}
if method.IsStreamingServer() {
p.ServerStreaming = proto.Bool(true)
}
return p
}
func fullNameOf(d protoreflect.Descriptor) *string {
if d == nil {
return nil
}
if strings.HasPrefix(string(d.FullName()), unknownPrefix) {
return proto.String(string(d.FullName()[len(unknownPrefix):]))
}
return proto.String("." + string(d.FullName()))
}

View File

@ -94,8 +94,7 @@ type Files struct {
// Note that enum values are in the top-level since that are in the same
// scope as the parent enum.
descsByName map[protoreflect.FullName]interface{}
filesByPath map[string][]protoreflect.FileDescriptor
numFiles int
filesByPath map[string]protoreflect.FileDescriptor
}
type packageDescriptor struct {
@ -118,16 +117,17 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
r.descsByName = map[protoreflect.FullName]interface{}{
"": &packageDescriptor{},
}
r.filesByPath = make(map[string][]protoreflect.FileDescriptor)
r.filesByPath = make(map[string]protoreflect.FileDescriptor)
}
path := file.Path()
if prev := r.filesByPath[path]; len(prev) > 0 {
if prev := r.filesByPath[path]; prev != nil {
r.checkGenProtoConflict(path)
err := errors.New("file %q is already registered", file.Path())
err = amendErrorWithCaller(err, prev[0], file)
if !(r == GlobalFiles && ignoreConflict(file, err)) {
return err
err = amendErrorWithCaller(err, prev, file)
if r == GlobalFiles && ignoreConflict(file, err) {
err = nil
}
return err
}
for name := file.Package(); name != ""; name = name.Parent() {
@ -168,8 +168,7 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
rangeTopLevelDescriptors(file, func(d protoreflect.Descriptor) {
r.descsByName[d.FullName()] = d
})
r.filesByPath[path] = append(r.filesByPath[path], file)
r.numFiles++
r.filesByPath[path] = file
return nil
}
@ -309,7 +308,6 @@ func (s *nameSuffix) Pop() (name protoreflect.Name) {
// FindFileByPath looks up a file by the path.
//
// This returns (nil, NotFound) if not found.
// This returns an error if multiple files have the same path.
func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error) {
if r == nil {
return nil, NotFound
@ -318,19 +316,13 @@ func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error)
globalMutex.RLock()
defer globalMutex.RUnlock()
}
fds := r.filesByPath[path]
switch len(fds) {
case 0:
return nil, NotFound
case 1:
return fds[0], nil
default:
return nil, errors.New("multiple files named %q", path)
if fd, ok := r.filesByPath[path]; ok {
return fd, nil
}
return nil, NotFound
}
// NumFiles reports the number of registered files,
// including duplicate files with the same name.
// NumFiles reports the number of registered files.
func (r *Files) NumFiles() int {
if r == nil {
return 0
@ -339,11 +331,10 @@ func (r *Files) NumFiles() int {
globalMutex.RLock()
defer globalMutex.RUnlock()
}
return r.numFiles
return len(r.filesByPath)
}
// RangeFiles iterates over all registered files while f returns true.
// If multiple files have the same name, RangeFiles iterates over all of them.
// The iteration order is undefined.
func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
if r == nil {
@ -353,11 +344,9 @@ func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
globalMutex.RLock()
defer globalMutex.RUnlock()
}
for _, files := range r.filesByPath {
for _, file := range files {
if !f(file) {
return
}
for _, file := range r.filesByPath {
if !f(file) {
return
}
}
}

File diff suppressed because it is too large Load Diff

17
vendor/modules.txt vendored
View File

@ -1,9 +1,9 @@
# github.com/cyrilix/robocar-base v0.1.6
# github.com/cyrilix/robocar-base v0.1.5
## explicit; go 1.17
github.com/cyrilix/robocar-base/cli
github.com/cyrilix/robocar-base/service
github.com/cyrilix/robocar-base/testtools
# github.com/cyrilix/robocar-protobuf/go v1.0.4
# github.com/cyrilix/robocar-protobuf/go v1.0.3
## explicit; go 1.17
github.com/cyrilix/robocar-protobuf/go/events
# github.com/eclipse/paho.mqtt.golang v1.3.5
@ -12,6 +12,7 @@ github.com/eclipse/paho.mqtt.golang
github.com/eclipse/paho.mqtt.golang/packets
# github.com/golang/protobuf v1.5.2
## explicit; go 1.9
github.com/golang/protobuf/proto
github.com/golang/protobuf/ptypes/timestamp
# github.com/gorilla/websocket v1.4.2
## explicit; go 1.12
@ -34,7 +35,7 @@ go.uber.org/zap/zapcore
## explicit; go 1.11
golang.org/x/net/internal/socks
golang.org/x/net/proxy
# google.golang.org/protobuf v1.27.1
# google.golang.org/protobuf v1.26.0
## explicit; go 1.9
google.golang.org/protobuf/encoding/prototext
google.golang.org/protobuf/encoding/protowire
@ -57,12 +58,14 @@ google.golang.org/protobuf/internal/set
google.golang.org/protobuf/internal/strs
google.golang.org/protobuf/internal/version
google.golang.org/protobuf/proto
google.golang.org/protobuf/reflect/protodesc
google.golang.org/protobuf/reflect/protoreflect
google.golang.org/protobuf/reflect/protoregistry
google.golang.org/protobuf/runtime/protoiface
google.golang.org/protobuf/runtime/protoimpl
google.golang.org/protobuf/types/descriptorpb
google.golang.org/protobuf/types/known/timestamppb
# periph.io/x/conn/v3 v3.6.10
# periph.io/x/conn/v3 v3.6.8
## explicit; go 1.13
periph.io/x/conn/v3
periph.io/x/conn/v3/driver
@ -77,7 +80,10 @@ periph.io/x/conn/v3/pin
periph.io/x/conn/v3/pin/pinreg
periph.io/x/conn/v3/spi
periph.io/x/conn/v3/spi/spireg
# periph.io/x/host/v3 v3.7.2
# periph.io/x/d2xx v0.0.3
## explicit; go 1.13
periph.io/x/d2xx
# periph.io/x/host/v3 v3.7.0
## explicit; go 1.13
periph.io/x/host/v3
periph.io/x/host/v3/allwinner
@ -90,6 +96,7 @@ periph.io/x/host/v3/chip
periph.io/x/host/v3/cpu
periph.io/x/host/v3/distro
periph.io/x/host/v3/fs
periph.io/x/host/v3/ftdi
periph.io/x/host/v3/odroidc1
periph.io/x/host/v3/pine64
periph.io/x/host/v3/pmem

380
vendor/periph.io/x/conn/v3/.gohci.yml generated vendored
View File

@ -17,87 +17,62 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: host
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../host
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- -short
- ./...
# Test in advance: devices
- dir: ..
cmd:
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -106,6 +81,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -135,87 +111,62 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: host
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../host
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- -short
- ./...
# Test in advance: devices
- dir: ..
cmd:
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -225,6 +176,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -267,87 +219,62 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: host
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../host
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- -short
- ./...
# Test in advance: devices
- dir: ..
cmd:
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -357,6 +284,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -415,87 +343,62 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: host
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../host
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- -short
- ./...
# Test in advance: devices
- dir: ..
cmd:
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -505,6 +408,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -529,87 +433,62 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: host
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../host
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- -short
- ./...
# Test in advance: devices
- dir: ..
cmd:
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -619,6 +498,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:

View File

@ -9,7 +9,8 @@ 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)
[![codecov](https://codecov.io/gh/periph/conn/branch/main/graph/badge.svg?token=1WIDCAJIK8)](https://codecov.io/gh/periph/conn)
[![Coverage
Status](https://codecov.io/gh/periph/conn/graph/badge.svg)](https://codecov.io/gh/periph/conn)
## Example

View File

@ -5,7 +5,6 @@
// This file contains the parallelized driver loading logic. It is meant to be
// load the drivers as fast as possible by parallelising work.
//go:build !tinygo
// +build !tinygo
package driverreg
@ -51,11 +50,9 @@ func initImpl() (*State, error) {
if err != nil {
return state, err
}
loaded := sync.Map{}
loaded := make(map[string]struct{}, len(byName))
for _, s := range stages {
// It's very important that each of the stage is fully completed before the
// next one is attempted.
s.loadParallel(&loaded, cD, cS, cE)
s.loadParallel(loaded, cD, cS, cE)
}
close(cD)
close(cS)
@ -64,9 +61,10 @@ func initImpl() (*State, error) {
return state, nil
}
// loadParallel loads all the drivers for this stage in parallel and returns
// once they are all loaded.
func (s *stage) loadParallel(loaded *sync.Map, cD chan<- driver.Impl, cS, cE chan<- DriverFailure) {
// 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)
@ -75,7 +73,7 @@ func (s *stage) loadParallel(loaded *sync.Map, cD chan<- driver.Impl, cS, cE cha
for name, drv := range s.drvs {
// Intentionally do not look at After(), only Prerequisites().
for _, dep := range drv.Prerequisites() {
if _, ok := loaded.Load(dep); !ok {
if _, ok := loaded[dep]; !ok {
cS <- DriverFailure{drv, errors.New("dependency not loaded: " + strconv.Quote(dep))}
continue loop
}
@ -100,6 +98,6 @@ func (s *stage) loadParallel(loaded *sync.Map, cD chan<- driver.Impl, cS, cE cha
wg.Wait()
}()
for s := range success {
loaded.Store(s, nil)
loaded[s] = struct{}{}
}
}

View File

@ -5,7 +5,6 @@
// This file contains the single threaded driver loading code, to be used on
// low performance cores.
//go:build tinygo
// +build tinygo
package driverreg

48
vendor/periph.io/x/d2xx/.gohci.yml generated vendored Normal file
View File

@ -0,0 +1,48 @@
# 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:
- checks:
- cmd:
- go
- test
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- go
- get
- periph.io/x/d2xx@${GIT_SHA}
dir: ../host
- cmd:
- go
- test
- ./...
dir: ../host
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/d2xx@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd

202
vendor/periph.io/x/d2xx/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.

44
vendor/periph.io/x/d2xx/README.md generated vendored Normal file
View File

@ -0,0 +1,44 @@
# d2xx
Package d2xx is a thin Go wrapper for the Future Technology "D2XX" driver at
https://ftdichip.com/drivers/d2xx-drivers/.
This package is not Go idiomatic. You will want to use
https://periph.io/x/host/v3/ftdi (or later) instead.
But if you really want, here it goes:
[![PkgGoDev](https://pkg.go.dev/badge/periph.io/x/d2xx)](https://pkg.go.dev/periph.io/x/d2xx)
This Go package includes third party software. See
[third_party/README.md](third_party/README.md).
## Configuration
See https://periph.io/device/ftdi/ to configure the host to be able to use this
driver.
## Availability
On darwin_amd64, linux_amd64 linux_arm (v6, v7 compatible) and linux_arm64 (v8),
cgo is required. If cgo is disabled (via `CGO_ENABLED=0`), all functions in this
driver return error [NoCGO](https://periph.io/x/d2xx#NoCGO).
On Windows, cgo is not required. If the dynamic library is not found at runtime,
[Missing](https://periph.io/x/d2xx#Missing) is returned.
## bcm2385
On linux_arm (v6), hard-float is required. For cross compilation, this
means arm-linux-gnueabihf-gcc is preferred to arm-linux-gnueabi-gcc. Using
hardfloat causes a segfault on Raspberry Pi 1, Zero and Zero Wireless. It is
recommended to disable this driver if targeting these hosts, see below.
## Disabling
To disable this driver, build with tag `no_d2xx`, e.g.
```
go install -tags no_d2xx periph.io/x/cmd/gpio-list@latest
```
This will behave has if cgo was disabled, even on Windows.

145
vendor/periph.io/x/d2xx/d2xx.go generated vendored Normal file
View File

@ -0,0 +1,145 @@
// 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.
package d2xx
import (
"strconv"
)
// Err is the error type returned by d2xx functions.
type Err int
// These are additional synthetic error codes.
const (
// NoCGO is returned when the package was compiled without cgo, thus the d2xx
// library is unavailable or the library was disabled via the `no_d2xx` build
// tag.
NoCGO Err = -2
// Missing is returned when the dynamic library is not available.
Missing Err = -1
)
// String converts a error integer to a string representation of the error.
func (e Err) String() string {
switch e {
case Missing:
// when the library d2xx couldn't be loaded at runtime.
return "couldn't load driver; visit https://periph.io/device/ftdi/ for help"
case NoCGO:
return "can't be used without cgo"
case 0: // FT_OK
return ""
case 1: // FT_INVALID_HANDLE
return "invalid handle"
case 2: // FT_DEVICE_NOT_FOUND
return "device not found; see https://periph.io/device/ftdi/ for help"
case 3: // FT_DEVICE_NOT_OPENED
return "device busy; see https://periph.io/device/ftdi/ for help"
case 4: // FT_IO_ERROR
return "I/O error"
case 5: // FT_INSUFFICIENT_RESOURCES
return "insufficient resources"
case 6: // FT_INVALID_PARAMETER
return "invalid parameter"
case 7: // FT_INVALID_BAUD_RATE
return "invalid baud rate"
case 8: // FT_DEVICE_NOT_OPENED_FOR_ERASE
return "device not opened for erase"
case 9: // FT_DEVICE_NOT_OPENED_FOR_WRITE
return "device not opened for write"
case 10: // FT_FAILED_TO_WRITE_DEVICE
return "failed to write device"
case 11: // FT_EEPROM_READ_FAILED
return "eeprom read failed"
case 12: // FT_EEPROM_WRITE_FAILED
return "eeprom write failed"
case 13: // FT_EEPROM_ERASE_FAILED
return "eeprom erase failed"
case 14: // FT_EEPROM_NOT_PRESENT
return "eeprom not present"
case 15: // FT_EEPROM_NOT_PROGRAMMED
return "eeprom not programmed"
case 16: // FT_INVALID_ARGS
return "invalid argument"
case 17: // FT_NOT_SUPPORTED
return "not supported"
case 18: // FT_OTHER_ERROR
return "other error"
case 19: // FT_DEVICE_LIST_NOT_READY
return "device list not ready"
default:
return "unknown status " + strconv.Itoa(int(e))
}
}
// unknown is a forward declaration of ftdi.DevType.
const unknown = 3
// handle is a d2xx handle.
//
// This is the base type which each OS specific implementation adds methods to.
type handle uintptr
// Handle is d2xx device handle.
type Handle interface {
Close() Err
// ResetDevice takes >1.2ms
ResetDevice() Err
GetDeviceInfo() (uint32, uint16, uint16, Err)
EEPROMRead(devType uint32, e *EEPROM) Err
EEPROMProgram(e *EEPROM) Err
EraseEE() Err
WriteEE(offset uint8, value uint16) Err
EEUASize() (int, Err)
EEUARead(ua []byte) Err
EEUAWrite(ua []byte) Err
SetChars(eventChar byte, eventEn bool, errorChar byte, errorEn bool) Err
SetUSBParameters(in, out int) Err
SetFlowControl() Err
SetTimeouts(readMS, writeMS int) Err
SetLatencyTimer(delayMS uint8) Err
SetBaudRate(hz uint32) Err
// GetQueueStatus takes >60µs
GetQueueStatus() (uint32, Err)
// Read takes <5µs if GetQueueStatus was called just before,
// 300µs~800µs otherwise (!)
Read(b []byte) (int, Err)
// Write takes >0.1ms
Write(b []byte) (int, Err)
GetBitMode() (byte, Err)
// SetBitMode takes >0.1ms
SetBitMode(mask, mode byte) Err
}
var _ Handle = handle(0)
// Version returns the library's version.
//
// 0, 0, 0 is returned if the library is unavailable.
func Version() (uint8, uint8, uint8) {
return version()
}
// CreateDeviceInfoList discovers the currently found devices.
//
// If the driver is disabled via build tag `no_d2xx`, or on posix
// `CGO_ENABLED=0` environment variable, NoCGO is returned.
//
// On Windows, Missing is returned if the dynamic library is not found at
// runtime.
func CreateDeviceInfoList() (int, Err) {
return createDeviceInfoList()
}
// Open opens the ith device discovered.
//
// If the driver is disabled via build tag `no_d2xx`, or on posix
// `CGO_ENABLED=0` environment variable, NoCGO is returned.
//
// On Windows, Missing is returned if the dynamic library is not found at
// runtime.
func Open(i int) (Handle, Err) {
return open(i)
}

13
vendor/periph.io/x/d2xx/d2xx_darwin_amd64.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// 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.
// +build cgo
// +build !no_d2xx
package d2xx
/*
#cgo LDFLAGS: -framework CoreFoundation -framework IOKit ${SRCDIR}/third_party/libftd2xx_darwin_amd64_v1.4.4.a
*/
import "C"

13
vendor/periph.io/x/d2xx/d2xx_linux_amd64.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// 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.
// +build cgo
// +build !no_d2xx
package d2xx
/*
#cgo LDFLAGS: ${SRCDIR}/third_party/libftd2xx_linux_amd64_v1.4.24.a
*/
import "C"

16
vendor/periph.io/x/d2xx/d2xx_linux_arm.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// 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.
// +build cgo
// +build !no_d2xx
package d2xx
// TODO(maruel): https://github.com/golang/go/issues/7211 would help target the
// optimal ARM architecture.
/*
#cgo LDFLAGS: ${SRCDIR}/third_party/libftd2xx_linux_arm6hf_v1.4.24.a
*/
import "C"

13
vendor/periph.io/x/d2xx/d2xx_linux_arm64.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// 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.
// +build cgo
// +build !no_d2xx
package d2xx
/*
#cgo LDFLAGS: ${SRCDIR}/third_party/libftd2xx_linux_arm64_v1.4.24.a
*/
import "C"

219
vendor/periph.io/x/d2xx/d2xx_posix.go generated vendored Normal file
View File

@ -0,0 +1,219 @@
// 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.
// +build cgo
// +build !windows
// +build !no_d2xx
package d2xx
/*
#include "third_party/ftd2xx.h"
#include <stdlib.h>
*/
import "C"
import (
"unsafe"
)
// Available is true if the library is available on this system.
const Available = true
// Library functions.
func version() (uint8, uint8, uint8) {
var v C.DWORD
C.FT_GetLibraryVersion(&v)
return uint8(v >> 16), uint8(v >> 8), uint8(v)
}
func createDeviceInfoList() (int, Err) {
var num C.DWORD
e := C.FT_CreateDeviceInfoList(&num)
return int(num), Err(e)
}
func open(i int) (Handle, Err) {
var h C.FT_HANDLE
e := C.FT_Open(C.int(i), &h)
if uintptr(h) == 0 && e == 0 {
// 18 means FT_OTHER_ERROR. Kind of a hack but better than panic.
e = 18
}
return handle(h), Err(e)
}
func (h handle) Close() Err {
return Err(C.FT_Close(h.toH()))
}
func (h handle) ResetDevice() Err {
return Err(C.FT_ResetDevice(h.toH()))
}
func (h handle) GetDeviceInfo() (uint32, uint16, uint16, Err) {
var dev C.FT_DEVICE
var id C.DWORD
if e := C.FT_GetDeviceInfo(h.toH(), &dev, &id, nil, nil, nil); e != 0 {
return unknown, 0, 0, Err(e)
}
return uint32(dev), uint16(id >> 16), uint16(id), 0
}
func (h handle) EEPROMRead(devType uint32, ee *EEPROM) Err {
var manufacturer [64]C.char
var manufacturerID [64]C.char
var desc [64]C.char
var serial [64]C.char
eepromVoid := unsafe.Pointer(&ee.Raw[0])
hdr := ee.asHeader()
// There something odd going on here.
//
// On a ft232h, we observed that hdr.DeviceType MUST NOT be set, but on a
// ft232r, it MUST be set. Since we can't know in advance what we must use,
// just try both. ¯\_(ツ)_/¯
hdr.DeviceType = devType
if e := C.FT_EEPROM_Read(h.toH(), eepromVoid, C.DWORD(len(ee.Raw)), &manufacturer[0], &manufacturerID[0], &desc[0], &serial[0]); e != 0 {
// FT_INVALID_PARAMETER
if e == 6 {
hdr.DeviceType = 0
e = C.FT_EEPROM_Read(h.toH(), eepromVoid, C.DWORD(len(ee.Raw)), &manufacturer[0], &manufacturerID[0], &desc[0], &serial[0])
}
if e != 0 {
return Err(e)
}
}
ee.Manufacturer = C.GoString(&manufacturer[0])
ee.ManufacturerID = C.GoString(&manufacturerID[0])
ee.Desc = C.GoString(&desc[0])
ee.Serial = C.GoString(&serial[0])
return 0
}
func (h handle) EEPROMProgram(ee *EEPROM) Err {
// len(manufacturer) + len(desc) <= 40.
/*
var cmanu [64]byte
copy(cmanu[:], ee.manufacturer)
var cmanuID [64]byte
copy(cmanuID[:], ee.manufacturerID)
var cdesc [64]byte
copy(cdesc[:], ee.desc)
var cserial [64]byte
copy(cserial[:], ee.serial)
*/
cmanu := C.CString(ee.Manufacturer)
defer C.free(unsafe.Pointer(cmanu))
cmanuID := C.CString(ee.ManufacturerID)
defer C.free(unsafe.Pointer(cmanuID))
cdesc := C.CString(ee.Desc)
defer C.free(unsafe.Pointer(cdesc))
cserial := C.CString(ee.Serial)
defer C.free(unsafe.Pointer(cserial))
if len(ee.Raw) == 0 {
return Err(C.FT_EEPROM_Program(h.toH(), unsafe.Pointer(uintptr(0)), 0, cmanu, cmanuID, cdesc, cserial))
}
return Err(C.FT_EEPROM_Program(h.toH(), unsafe.Pointer(&ee.Raw[0]), C.DWORD(len(ee.Raw)), cmanu, cmanuID, cdesc, cserial))
}
func (h handle) EraseEE() Err {
return Err(C.FT_EraseEE(h.toH()))
}
func (h handle) WriteEE(offset uint8, value uint16) Err {
return Err(C.FT_WriteEE(h.toH(), C.DWORD(offset), C.WORD(value)))
}
func (h handle) EEUASize() (int, Err) {
var size C.DWORD
if e := C.FT_EE_UASize(h.toH(), &size); e != 0 {
return 0, Err(e)
}
return int(size), 0
}
func (h handle) EEUARead(ua []byte) Err {
var size C.DWORD
if e := C.FT_EE_UARead(h.toH(), (*C.UCHAR)(unsafe.Pointer(&ua[0])), C.DWORD(len(ua)), &size); e != 0 {
return Err(e)
}
if int(size) != len(ua) {
return 6 // FT_INVALID_PARAMETER
}
return 0
}
func (h handle) EEUAWrite(ua []byte) Err {
if e := C.FT_EE_UAWrite(h.toH(), (*C.UCHAR)(&ua[0]), C.DWORD(len(ua))); e != 0 {
return Err(e)
}
return 0
}
func (h handle) SetChars(eventChar byte, eventEn bool, errorChar byte, errorEn bool) Err {
v := C.UCHAR(0)
if eventEn {
v = 1
}
w := C.UCHAR(0)
if errorEn {
w = 1
}
return Err(C.FT_SetChars(h.toH(), C.UCHAR(eventChar), v, C.UCHAR(errorChar), w))
}
func (h handle) SetUSBParameters(in, out int) Err {
return Err(C.FT_SetUSBParameters(h.toH(), C.DWORD(in), C.DWORD(out)))
}
func (h handle) SetFlowControl() Err {
return Err(C.FT_SetFlowControl(h.toH(), C.FT_FLOW_RTS_CTS, 0, 0))
}
func (h handle) SetTimeouts(readMS, writeMS int) Err {
return Err(C.FT_SetTimeouts(h.toH(), C.DWORD(readMS), C.DWORD(writeMS)))
}
func (h handle) SetLatencyTimer(delayMS uint8) Err {
return Err(C.FT_SetLatencyTimer(h.toH(), C.UCHAR(delayMS)))
}
func (h handle) SetBaudRate(hz uint32) Err {
return Err(C.FT_SetBaudRate(h.toH(), C.DWORD(hz)))
}
func (h handle) GetQueueStatus() (uint32, Err) {
var v C.DWORD
e := C.FT_GetQueueStatus(h.toH(), &v)
return uint32(v), Err(e)
}
func (h handle) Read(b []byte) (int, Err) {
var bytesRead C.DWORD
e := C.FT_Read(h.toH(), C.LPVOID(unsafe.Pointer(&b[0])), C.DWORD(len(b)), &bytesRead)
return int(bytesRead), Err(e)
}
func (h handle) Write(b []byte) (int, Err) {
var bytesSent C.DWORD
e := C.FT_Write(h.toH(), C.LPVOID(unsafe.Pointer(&b[0])), C.DWORD(len(b)), &bytesSent)
return int(bytesSent), Err(e)
}
func (h handle) GetBitMode() (byte, Err) {
var s C.UCHAR
e := C.FT_GetBitMode(h.toH(), &s)
return uint8(s), Err(e)
}
func (h handle) SetBitMode(mask, mode byte) Err {
return Err(C.FT_SetBitMode(h.toH(), C.UCHAR(mask), C.UCHAR(mode)))
}
func (h handle) toH() C.FT_HANDLE {
return C.FT_HANDLE(h)
}

109
vendor/periph.io/x/d2xx/d2xx_posix_no_cgo.go generated vendored Normal file
View File

@ -0,0 +1,109 @@
// 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.
// +build !cgo no_d2xx
// +build !windows no_d2xx
package d2xx
// Available is true if the library is available on this system.
const Available = false
// Library functions.
func version() (uint8, uint8, uint8) {
return 0, 0, 0
}
func createDeviceInfoList() (int, Err) {
return 0, NoCGO
}
func open(i int) (Handle, Err) {
return handle(0), NoCGO
}
func (h handle) Close() Err {
return NoCGO
}
func (h handle) ResetDevice() Err {
return NoCGO
}
func (h handle) GetDeviceInfo() (uint32, uint16, uint16, Err) {
return unknown, 0, 0, NoCGO
}
func (h handle) EEPROMRead(devType uint32, ee *EEPROM) Err {
return NoCGO
}
func (h handle) EEPROMProgram(e *EEPROM) Err {
return NoCGO
}
func (h handle) EraseEE() Err {
return NoCGO
}
func (h handle) WriteEE(offset uint8, value uint16) Err {
return NoCGO
}
func (h handle) EEUASize() (int, Err) {
return 0, NoCGO
}
func (h handle) EEUARead(ua []byte) Err {
return NoCGO
}
func (h handle) EEUAWrite(ua []byte) Err {
return NoCGO
}
func (h handle) SetChars(eventChar byte, eventEn bool, errorChar byte, errorEn bool) Err {
return NoCGO
}
func (h handle) SetUSBParameters(in, out int) Err {
return NoCGO
}
func (h handle) SetFlowControl() Err {
return NoCGO
}
func (h handle) SetTimeouts(readMS, writeMS int) Err {
return NoCGO
}
func (h handle) SetLatencyTimer(delayMS uint8) Err {
return NoCGO
}
func (h handle) SetBaudRate(hz uint32) Err {
return NoCGO
}
func (h handle) GetQueueStatus() (uint32, Err) {
return 0, NoCGO
}
func (h handle) Read(b []byte) (int, Err) {
return 0, NoCGO
}
func (h handle) Write(b []byte) (int, Err) {
return 0, NoCGO
}
func (h handle) GetBitMode() (byte, Err) {
return 0, NoCGO
}
func (h handle) SetBitMode(mask, mode byte) Err {
return NoCGO
}

19
vendor/periph.io/x/d2xx/d2xx_posix_other.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
// 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.
// +build cgo
// +build !darwin,!amd64
// +build !linux,!amd64
// +build !linux,!arm
// +build !windows
// +build !no_d2xx
package d2xx
// This assumes the library is installed and available for linking.
/*
#cgo LDFLAGS: -lftd2xx
*/
import "C"

281
vendor/periph.io/x/d2xx/d2xx_windows.go generated vendored Normal file
View File

@ -0,0 +1,281 @@
// 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.
// +build !no_d2xx
package d2xx
import (
"bytes"
"syscall"
"unsafe"
)
// Available is true if the library is available on this system.
var Available = false
func version() (uint8, uint8, uint8) {
var v uint32
if pGetLibraryVersion != nil {
_, _, _ = pGetLibraryVersion.Call(uintptr(unsafe.Pointer(&v)))
}
return uint8(v >> 16), uint8(v >> 8), uint8(v)
}
func createDeviceInfoList() (int, Err) {
if pCreateDeviceInfoList != nil {
var num uint32
r1, _, _ := pCreateDeviceInfoList.Call(uintptr(unsafe.Pointer(&num)))
return int(num), Err(r1)
}
return 0, Missing
}
func open(i int) (Handle, Err) {
var h handle
if pOpen != nil {
r1, _, _ := pOpen.Call(uintptr(i), uintptr(unsafe.Pointer(&h)))
return h, Err(r1)
}
return h, Missing
}
func (h handle) Close() Err {
r1, _, _ := pClose.Call(h.toH())
return Err(r1)
}
func (h handle) ResetDevice() Err {
r1, _, _ := pResetDevice.Call(h.toH())
return Err(r1)
}
func (h handle) GetDeviceInfo() (uint32, uint16, uint16, Err) {
var d uint32
var id uint32
if r1, _, _ := pGetDeviceInfo.Call(h.toH(), uintptr(unsafe.Pointer(&d)), uintptr(unsafe.Pointer(&id)), 0, 0, 0); r1 != 0 {
return unknown, 0, 0, Err(r1)
}
return d, uint16(id >> 16), uint16(id), 0
}
func (h handle) EEPROMRead(devType uint32, ee *EEPROM) Err {
var manufacturer [64]byte
var manufacturerID [64]byte
var desc [64]byte
var serial [64]byte
// Shortcuts.
m := uintptr(unsafe.Pointer(&manufacturer[0]))
mi := uintptr(unsafe.Pointer(&manufacturerID[0]))
de := uintptr(unsafe.Pointer(&desc[0]))
s := uintptr(unsafe.Pointer(&serial[0]))
eepromVoid := unsafe.Pointer(&ee.Raw[0])
hdr := ee.asHeader()
// It MUST be set here. This is not always the case on posix.
hdr.DeviceType = devType
if r1, _, _ := pEEPROMRead.Call(h.toH(), uintptr(eepromVoid), uintptr(len(ee.Raw)), m, mi, de, s); r1 != 0 {
return Err(r1)
}
ee.Manufacturer = toStr(manufacturer[:])
ee.ManufacturerID = toStr(manufacturerID[:])
ee.Desc = toStr(desc[:])
ee.Serial = toStr(serial[:])
return 0
}
func (h handle) EEPROMProgram(ee *EEPROM) Err {
var cmanu [64]byte
copy(cmanu[:], ee.Manufacturer)
var cmanuID [64]byte
copy(cmanuID[:], ee.ManufacturerID)
var cdesc [64]byte
copy(cdesc[:], ee.Desc)
var cserial [64]byte
copy(cserial[:], ee.Serial)
r1, _, _ := pEEPROMProgram.Call(h.toH(), uintptr(unsafe.Pointer(&ee.Raw[0])), uintptr(len(ee.Raw)), uintptr(unsafe.Pointer(&cmanu[0])), uintptr(unsafe.Pointer(&cmanuID[0])), uintptr(unsafe.Pointer(&cdesc[0])), uintptr(unsafe.Pointer(&cserial[0])))
return Err(r1)
}
func (h handle) EraseEE() Err {
r1, _, _ := pEraseEE.Call(h.toH())
return Err(r1)
}
func (h handle) WriteEE(offset uint8, value uint16) Err {
r1, _, _ := pWriteEE.Call(h.toH(), uintptr(offset), uintptr(value))
return Err(r1)
}
func (h handle) EEUASize() (int, Err) {
var size uint32
if r1, _, _ := pEEUASize.Call(h.toH(), uintptr(unsafe.Pointer(&size))); r1 != 0 {
return 0, Err(r1)
}
return int(size), 0
}
func (h handle) EEUARead(ua []byte) Err {
var size uint32
if r1, _, _ := pEEUARead.Call(h.toH(), uintptr(unsafe.Pointer(&ua[0])), uintptr(len(ua)), uintptr(unsafe.Pointer(&size))); r1 != 0 {
return Err(r1)
}
if int(size) != len(ua) {
return 6 // FT_INVALID_PARAMETER
}
return 0
}
func (h handle) EEUAWrite(ua []byte) Err {
r1, _, _ := pEEUAWrite.Call(h.toH(), uintptr(unsafe.Pointer(&ua[0])), uintptr(len(ua)))
return Err(r1)
}
func (h handle) SetChars(eventChar byte, eventEn bool, errorChar byte, errorEn bool) Err {
v := uintptr(0)
if eventEn {
v = 1
}
w := uintptr(0)
if errorEn {
w = 1
}
r1, _, _ := pSetChars.Call(h.toH(), uintptr(eventChar), v, uintptr(errorChar), w)
return Err(r1)
}
func (h handle) SetUSBParameters(in, out int) Err {
r1, _, _ := pSetUSBParameters.Call(h.toH(), uintptr(in), uintptr(out))
return Err(r1)
}
func (h handle) SetFlowControl() Err {
// FT_FLOW_RTS_CTS
r1, _, _ := pSetFlowControl.Call(h.toH(), 0x0100, 0, 0)
return Err(r1)
}
func (h handle) SetTimeouts(readMS, writeMS int) Err {
r1, _, _ := pSetTimeouts.Call(h.toH(), uintptr(readMS), uintptr(writeMS))
return Err(r1)
}
func (h handle) SetLatencyTimer(delayMS uint8) Err {
r1, _, _ := pSetLatencyTimer.Call(h.toH(), uintptr(delayMS))
return Err(r1)
}
func (h handle) SetBaudRate(hz uint32) Err {
r1, _, _ := pSetBaudRate.Call(h.toH(), uintptr(hz))
return Err(r1)
}
func (h handle) GetQueueStatus() (uint32, Err) {
var v uint32
r1, _, _ := pGetQueueStatus.Call(h.toH(), uintptr(unsafe.Pointer(&v)))
return v, Err(r1)
}
func (h handle) Read(b []byte) (int, Err) {
var bytesRead uint32
r1, _, _ := pRead.Call(h.toH(), uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(unsafe.Pointer(&bytesRead)))
return int(bytesRead), Err(r1)
}
func (h handle) Write(b []byte) (int, Err) {
var bytesSent uint32
r1, _, _ := pWrite.Call(h.toH(), uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(unsafe.Pointer(&bytesSent)))
return int(bytesSent), Err(r1)
}
func (h handle) GetBitMode() (byte, Err) {
var s uint8
r1, _, _ := pGetBitMode.Call(h.toH(), uintptr(unsafe.Pointer(&s)))
return s, Err(r1)
}
func (h handle) SetBitMode(mask, mode byte) Err {
r1, _, _ := pSetBitMode.Call(h.toH(), uintptr(mask), uintptr(mode))
return Err(r1)
}
func (h handle) toH() uintptr {
return uintptr(h)
}
//
var (
pClose *syscall.Proc
pCreateDeviceInfoList *syscall.Proc
pEEPROMRead *syscall.Proc
pEEPROMProgram *syscall.Proc
pEraseEE *syscall.Proc
pWriteEE *syscall.Proc
pEEUASize *syscall.Proc
pEEUARead *syscall.Proc
pEEUAWrite *syscall.Proc
pGetBitMode *syscall.Proc
pGetDeviceInfo *syscall.Proc
pGetLibraryVersion *syscall.Proc
pGetQueueStatus *syscall.Proc
pOpen *syscall.Proc
pRead *syscall.Proc
pResetDevice *syscall.Proc
pSetBaudRate *syscall.Proc
pSetBitMode *syscall.Proc
pSetChars *syscall.Proc
pSetFlowControl *syscall.Proc
pSetLatencyTimer *syscall.Proc
pSetTimeouts *syscall.Proc
pSetUSBParameters *syscall.Proc
pWrite *syscall.Proc
)
func init() {
if dll, _ := syscall.LoadDLL("ftd2xx.dll"); dll != nil {
// If any function is not found, disable the support.
Available = true
find := func(n string) *syscall.Proc {
s, _ := dll.FindProc(n)
if s == nil {
Available = false
}
return s
}
pClose = find("FT_Close")
pCreateDeviceInfoList = find("FT_CreateDeviceInfoList")
pEEPROMRead = find("FT_EEPROM_Read")
pEEPROMProgram = find("FT_EEPROM_Program")
pEraseEE = find("FT_EraseEE")
pWriteEE = find("FT_WriteEE")
pEEUASize = find("FT_EE_UASize")
pEEUARead = find("FT_EE_UARead")
pEEUAWrite = find("FT_EE_UAWrite")
pGetBitMode = find("FT_GetBitMode")
pGetDeviceInfo = find("FT_GetDeviceInfo")
pGetLibraryVersion = find("FT_GetLibraryVersion")
pGetQueueStatus = find("FT_GetQueueStatus")
pOpen = find("FT_Open")
pRead = find("FT_Read")
pResetDevice = find("FT_ResetDevice")
pSetBaudRate = find("FT_SetBaudRate")
pSetBitMode = find("FT_SetBitMode")
pSetChars = find("FT_SetChars")
pSetFlowControl = find("FT_SetFlowControl")
pSetLatencyTimer = find("FT_SetLatencyTimer")
pSetTimeouts = find("FT_SetTimeouts")
pSetUSBParameters = find("FT_SetUSBParameters")
pWrite = find("FT_Write")
}
}
func toStr(c []byte) string {
i := bytes.IndexByte(c, 0)
if i != -1 {
return string(c[:i])
}
return string(c)
}

18
vendor/periph.io/x/d2xx/doc.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// 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 d2xx is a thin Go wrapper for the Future Technology "D2XX" driver.
//
// This package is not Go idiomatic. You want to use
// https://periph.io/x/host/v3/ftdi (or later) instead.
//
// A static library of the d2xx driver is included for linux and macOS. They are
// from https://ftdichip.com/drivers/d2xx-drivers/. See third_party/README.md
// for more details.
//
// Configuration
//
// See https://periph.io/device/ftdi/ for more details, and how to configure
// the host to be able to use this driver.
package d2xx

39
vendor/periph.io/x/d2xx/eeprom.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
// 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 d2xx
import (
"unsafe"
)
// EEPROM is the unprocessed EEPROM content.
//
// The EEPROM is in 3 parts: the defined struct, the 4 strings and the rest
// which is used as an 'user area'. The size of the user area depends on the
// length of the strings. The user area content is not included in this struct.
type EEPROM struct {
// Raw is the raw EEPROM content. It excludes the strings.
Raw []byte
// The following condition must be true: len(Manufacturer) + len(Desc) <= 40.
Manufacturer string
ManufacturerID string
Desc string
Serial string
}
func (e *EEPROM) asHeader() *eepromHeader {
// sizeof(EEPROMHeader)
if len(e.Raw) < 16 {
return nil
}
return (*eepromHeader)(unsafe.Pointer(&e.Raw[0]))
}
// eepromHeader is the common 16 bytes header.
type eepromHeader struct {
DeviceType uint32
// The rest is not necessary here so it is skipped.
}

43
vendor/periph.io/x/d2xx/test.sh generated vendored Normal file
View File

@ -0,0 +1,43 @@
#!/bin/bash
# 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.
# Builds the package on multiple OSes to confirm it builds fine.
set -eu
cd `dirname $0`
OPT=$*
# Do not set CGO_ENABLED, as we want the default behavior when cross compiling,
# which is different from when CGO_ENABLED=1.
export -n CGO_ENABLED
# Cleanup.
export -n GOOS
export -n GOARCH
function build {
export GOOS=$1
export GOARCH=$2
echo "Building on $GOOS/$GOARCH"
go build $OPT
echo "Building on $GOOS/$GOARCH - no_d2xx"
go build -tags no_d2xx $OPT
echo "Building on $GOOS/$GOARCH - no cgo"
CGO_ENABLED=0 go build $OPT
echo "Building on $GOOS/$GOARCH - no cgo, no_d2xx"
CGO_ENABLED=0 go build -tags no_d2xx $OPT
}
CGO_ENABLED=1 CC=x86_64-linux-gnu-gcc build linux amd64
# Requires: sudo apt install gcc-arm-linux-gnueabihf
CGO_ENABLED=1 CC=arm-linux-gnueabihf-gcc build linux arm
# Requires: sudo apt install gcc-aarch64-linux-gnu
CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc build linux arm64
build linux 386
build windows amd64
build darwin amd64

285
vendor/periph.io/x/host/v3/.gohci.yml generated vendored
View File

@ -17,61 +17,44 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: devices
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -80,6 +63,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -109,61 +93,44 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: devices
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -173,6 +140,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -215,61 +183,44 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: devices
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -279,6 +230,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -325,11 +277,6 @@ workers:
- periph-smoketest
- bcm283x
- -quick
- cmd:
- periph-smoketest
- ftdi
- -type
- ft232h
# Old MacBook Pro on 10.9.
- name: mbp
@ -342,61 +289,44 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: devices
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -406,6 +336,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -418,11 +349,11 @@ workers:
- i2c-list
- cmd:
- spi-list
- cmd:
- periph-smoketest
- ftdi
- -type
- ft232r
# - cmd:
# - periph-smoketest
# - ftdi
# - -type
# - ft232r
# Laptop on Windows 10.
- name: win10
@ -435,61 +366,44 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance: devices
- dir: ..
cmd:
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../devices
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../devices
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- -short
- ./...
# Test in advance: cmd
- dir: ..
cmd:
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/host/v3=../host
- dir: ../cmd
cmd:
dir: ..
- cmd:
- go
- get
- -t
- ./...
- dir: ../cmd
cmd:
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- dir: ../cmd
cmd:
- cmd:
- go
- install
- -v
@ -499,6 +413,7 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -511,8 +426,8 @@ workers:
- i2c-list
- cmd:
- spi-list
- cmd:
- periph-smoketest
- ftdi
- -type
- ft232h
# - cmd:
# - periph-smoketest
# - ftdi
# - -type
# - ft232h

View File

@ -9,7 +9,8 @@ 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/host/v3)](https://pkg.go.dev/periph.io/x/host/v3)
[![codecov](https://codecov.io/gh/periph/host/branch/main/graph/badge.svg?token=RX9O1CPQHU)](https://codecov.io/gh/periph/host)
[![Coverage
Status](https://codecov.io/gh/periph/host/graph/badge.svg)](https://codecov.io/gh/periph/host)
## Example

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build arm64
// +build arm64
package allwinner

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm && !arm64
// +build !arm,!arm64
package allwinner

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm
// +build !arm
package am335x

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build arm64
// +build arm64
package bcm283x

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm && !arm64
// +build !arm,!arm64
package bcm283x

View File

@ -406,8 +406,8 @@ func (p *Pin) In(pull gpio.Pull, edge gpio.Edge) error {
// https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
// page 101.
// However, BCM2711 uses a simpler way of setting pull resistors, reference at
// https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf
// page 65 and 73 ~ 76.
// https://github.com/raspberrypi/documentation/blob/master/hardware/raspberrypi/bcm2711/rpi_DATA_2711_1p0.pdf
// page 84 and 95 ~ 98.
// If we are running on a newer chip such as BCM2711, set Pull directly.
if !drvGPIO.useLegacyPull {
@ -431,10 +431,7 @@ func (p *Pin) In(pull gpio.Pull, edge gpio.Edge) error {
case gpio.Float:
pullState = 0
}
bitOffset := 2 * uint(p.number%16)
previous := drvGPIO.gpioMemory.pullRegister[offset] & ^(3 << bitOffset)
drvGPIO.gpioMemory.pullRegister[offset] = previous | (pullState << bitOffset)
drvGPIO.gpioMemory.pullRegister[offset] = pullState << uint((p.number%16)<<1)
} else {
// Set Pull
switch pull {
@ -1027,8 +1024,9 @@ type function uint8
// Mapping as
// https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
// pages 90-91.
// And https://datasheets.raspberrypi.org/bcm2711/bcm2711-peripherals.pdf pages
// 65 and 73 ~ 76.
// And
// https://github.com/raspberrypi/documentation/blob/master/hardware/raspberrypi/bcm2711/rpi_DATA_2711_1p0.pdf
// pages 83-84.
type gpioMap struct {
// 0x00 RW GPIO Function Select 0 (GPIO0-9)
// 0x04 RW GPIO Function Select 1 (GPIO10-19)

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm
// +build !arm
package black

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm
// +build !arm
package bone

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm
// +build !arm
package green

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm
// +build !arm
package chip

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !linux
// +build !linux
package cpu

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build arm64
// +build arm64
package distro

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm && !arm64
// +build !arm,!arm64
package distro

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !linux
// +build !linux
package distro

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !linux
// +build !linux
package fs

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build mips || mipsle
// +build mips mipsle
package fs

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !mips && !mipsle
// +build !mips,!mipsle
package fs

878
vendor/periph.io/x/host/v3/ftdi/dev.go generated vendored Normal file
View File

@ -0,0 +1,878 @@
// 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 ftdi
import (
"context"
"errors"
"strconv"
"sync"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/spi"
)
// Info is the information gathered about the connected FTDI device.
//
// The data is gathered from the USB descriptor.
type Info struct {
// Opened is true if the device was successfully opened.
Opened bool
// Type is the FTDI device type.
//
// The value can be "FT232H", "FT232R", etc.
//
// An empty string means the type is unknown.
Type string
// VenID is the vendor ID from the USB descriptor information. It is expected
// to be 0x0403 (FTDI).
VenID uint16
// DevID is the product ID from the USB descriptor information. It is
// expected to be one of 0x6001, 0x6006, 0x6010, 0x6014.
DevID uint16
}
// Dev represents one FTDI device.
//
// There can be multiple FTDI devices connected to a host.
//
// The device may also export one or multiple of I²C, SPI buses. You need to
// either cast into the right hardware, but more simply use the i2creg / spireg
// bus/port registries.
type Dev interface {
// conn.Resource
String() string
Halt() error
// Info returns information about an opened device.
Info(i *Info)
// Header returns the GPIO pins exposed on the chip.
Header() []gpio.PinIO
// SetSpeed sets the base clock for all I/O transactions.
//
// The device defaults to its fastest speed.
SetSpeed(f physic.Frequency) error
// EEPROM returns the EEPROM content.
EEPROM(ee *EEPROM) error
// WriteEEPROM updates the EEPROM. Must be used carefully.
WriteEEPROM(ee *EEPROM) error
// EraseEEPROM erases the EEPROM. Must be used carefully.
EraseEEPROM() error
// UserArea reads and return the EEPROM part that can be used to stored user
// defined values.
UserArea() ([]byte, error)
// WriteUserArea updates the user area in the EEPROM.
//
// If the length of ua is less than the available space, is it zero extended.
WriteUserArea(ua []byte) error
}
// broken represents a device that couldn't be opened correctly.
//
// It returns an error message to help the user diagnose issues.
type broken struct {
index int
err error
name string
}
func (b *broken) String() string {
return b.name
}
func (b *broken) Halt() error {
return nil
}
func (b *broken) Info(i *Info) {
i.Opened = false
}
func (b *broken) Header() []gpio.PinIO {
return nil
}
func (b *broken) SetSpeed(f physic.Frequency) error {
return b.err
}
func (b *broken) EEPROM(ee *EEPROM) error {
return b.err
}
func (b *broken) WriteEEPROM(ee *EEPROM) error {
return b.err
}
func (b *broken) EraseEEPROM() error {
return b.err
}
func (b *broken) UserArea() ([]byte, error) {
return nil, b.err
}
func (b *broken) WriteUserArea(ua []byte) error {
return b.err
}
// generic represents a generic FTDI device.
//
// It is used for the models that this package doesn't fully support yet.
type generic struct {
// Immutable after initialization.
index int
h *handle
name string
}
func (f *generic) String() string {
return f.name
}
// Halt implements conn.Resource.
//
// This halts all operations going through this device.
func (f *generic) Halt() error {
return f.h.Reset()
}
// Info returns information about an opened device.
func (f *generic) Info(i *Info) {
i.Opened = true
i.Type = f.h.t.String()
i.VenID = f.h.venID
i.DevID = f.h.devID
}
// Header returns the GPIO pins exposed on the chip.
func (f *generic) Header() []gpio.PinIO {
return nil
}
func (f *generic) SetSpeed(freq physic.Frequency) error {
// TODO(maruel): Doc says the actual speed is 16x, confirm.
return f.h.SetBaudRate(freq)
}
func (f *generic) EEPROM(ee *EEPROM) error {
return f.h.ReadEEPROM(ee)
/*
if f.ee.Raw == nil {
if err := f.h.readEEPROM(&f.ee); err != nil {
return nil
}
if f.ee.Raw == nil {
// It's a fresh new device. Devices bought via Adafruit already have
// their EEPROM programmed with Adafruit branding but devices sold by
// CJMCU are not. Since d2xxGetDeviceInfo() above succeeded, we know the
// device type via the USB descriptor, which is sufficient to load the
// driver, which permits to program the EEPROM to "bootstrap" it.
f.ee.Raw = []byte{}
}
}
*ee = f.ee
return nil
*/
}
func (f *generic) WriteEEPROM(ee *EEPROM) error {
// TODO(maruel): Compare with the cached EEPROM, and only update the
// different values if needed so reduce the EEPROM wear.
// f.h.h.d2xxWriteEE()
return f.h.WriteEEPROM(ee)
}
func (f *generic) EraseEEPROM() error {
return f.h.EraseEEPROM()
}
func (f *generic) UserArea() ([]byte, error) {
return f.h.ReadUA()
}
func (f *generic) WriteUserArea(ua []byte) error {
return f.h.WriteUA(ua)
}
//
func newFT232H(g generic) (*FT232H, error) {
f := &FT232H{
generic: g,
cbus: gpiosMPSSE{h: g.h, cbus: true},
dbus: gpiosMPSSE{h: g.h},
c8: invalidPin{num: 16, n: g.name + ".C8"}, // , dp: gpio.PullUp
c9: invalidPin{num: 17, n: g.name + ".C9"}, // , dp: gpio.PullUp
}
f.cbus.init(f.name)
f.dbus.init(f.name)
for i := range f.dbus.pins {
f.hdr[i] = &f.dbus.pins[i]
}
for i := range f.cbus.pins {
f.hdr[i+8] = &f.cbus.pins[i]
}
// TODO(maruel): C8 and C9 can be used when their mux in the EEPROM is set to
// ft232hCBusIOMode.
f.hdr[16] = &f.c8
f.hdr[17] = &f.c9
f.D0 = f.hdr[0]
f.D1 = f.hdr[1]
f.D2 = f.hdr[2]
f.D3 = f.hdr[3]
f.D4 = f.hdr[4]
f.D5 = f.hdr[5]
f.D6 = f.hdr[6]
f.D7 = f.hdr[7]
f.C0 = f.hdr[8]
f.C1 = f.hdr[9]
f.C2 = f.hdr[10]
f.C3 = f.hdr[11]
f.C4 = f.hdr[12]
f.C5 = f.hdr[13]
f.C6 = f.hdr[14]
f.C7 = f.hdr[15]
f.C8 = f.hdr[16]
f.C9 = f.hdr[17]
// This function forces all pins as inputs.
if err := f.h.InitMPSSE(); err != nil {
return nil, err
}
f.s.c.f = f
f.i.f = f
return f, nil
}
// FT232H represents a FT232H device.
//
// It implements Dev.
//
// The FT232H has 1024 bytes output buffer and 1024 bytes input buffer. It
// supports 512 bytes USB packets.
//
// The device can be used in a few different modes, two modes are supported:
//
// - D0~D3 as a serial protocol (MPSEE), supporting I²C and SPI (and eventually
// UART), In this mode, D4~D7 and C0~C7 can be used as synchronized GPIO.
//
// - D0~D7 as a synchronous 8 bits bit-bang port. In this mode, only a few pins
// on CBus are usable in slow mode.
//
// Each group of pins D0~D7 and C0~C7 can be changed at once in one pass via
// DBus() or CBus().
//
// This enables usage as an 8 bit parallel port.
//
// Pins C8 and C9 can only be used in 'slow' mode via EEPROM and are currently
// not implemented.
//
// Datasheet
//
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf
type FT232H struct {
generic
D0 gpio.PinIO // Clock output
D1 gpio.PinIO // Data out
D2 gpio.PinIO // Data in
D3 gpio.PinIO // Chip select
D4 gpio.PinIO
D5 gpio.PinIO
D6 gpio.PinIO
D7 gpio.PinIO
C0 gpio.PinIO
C1 gpio.PinIO
C2 gpio.PinIO
C3 gpio.PinIO
C4 gpio.PinIO
C5 gpio.PinIO
C6 gpio.PinIO
C7 gpio.PinIO
C8 gpio.PinIO // Not implemented
C9 gpio.PinIO // Not implemented
hdr [18]gpio.PinIO
cbus gpiosMPSSE
dbus gpiosMPSSE
c8 invalidPin // gpio.PullUp
c9 invalidPin // gpio.PullUp
mu sync.Mutex
usingI2C bool
usingSPI bool
i i2cBus
s spiMPSEEPort
// TODO(maruel): Technically speaking, a SPI port could be hacked up too in
// sync bit-bang but there's less point when MPSEE is available.
}
// Header returns the GPIO pins exposed on the chip.
func (f *FT232H) Header() []gpio.PinIO {
out := make([]gpio.PinIO, len(f.hdr))
copy(out, f.hdr[:])
return out
}
func (f *FT232H) SetSpeed(freq physic.Frequency) error {
// TODO(maruel): When using MPSEE, use the MPSEE command. If using sync
// bit-bang, use SetBaudRate().
// TODO(maruel): Doc says the actual speed is 16x, confirm.
return f.h.SetBaudRate(freq)
}
// CBus sets the values of C0 to C7 in the specified direction and value.
//
// 0 direction means input, 1 means output.
func (f *FT232H) CBus(direction, value byte) error {
return f.h.MPSSECBus(direction, value)
}
// DBus sets the values of D0 to d7 in the specified direction and value.
//
// 0 direction means input, 1 means output.
//
// This function must be used to set Clock idle level.
func (f *FT232H) DBus(direction, value byte) error {
return f.h.MPSSEDBus(direction, value)
}
// CBusRead reads the values of C0 to C7.
func (f *FT232H) CBusRead() (byte, error) {
return f.h.MPSSECBusRead()
}
// DBusRead reads the values of D0 to D7.
func (f *FT232H) DBusRead() (byte, error) {
return f.h.MPSSEDBusRead()
}
// I2C returns an I²C bus over the AD bus.
//
// pull can be either gpio.PullUp or gpio.Float. The recommended pull up
// resistors are 10kΩ for 100kHz and 2kΩ for 400kHz when using Float. The
// GPIO's pull up is 75kΩ, which may require using a lower speed for signal
// reliability. Optimal pull up resistor calculation depends on the capacitance.
//
// It uses D0, D1 and D2.
//
// D0 is SCL. It must to be pulled up externally.
//
// D1 and D2 are used for SDA. D1 is the output using open drain, D2 is the
// input. D1 and D2 must be wired together and must be pulled up externally.
//
// It is recommended to set the mode to 245 FIFO in the EEPROM of the FT232H.
//
// The FIFO mode is recommended because it allows the ADbus lines to start as
// tristate. If the chip starts in the default UART mode, then the ADbus lines
// will be in the default UART idle states until the application opens the port
// and configures it as MPSSE. Care should also be taken that the RD# input on
// ACBUS is not asserted in this initial state as this can cause the FIFO lines
// to drive out.
func (f *FT232H) I2C(pull gpio.Pull) (i2c.BusCloser, error) {
if pull != gpio.PullUp && pull != gpio.Float {
return nil, errors.New("d2xx: I²C pull can only be PullUp or Float")
}
f.mu.Lock()
defer f.mu.Unlock()
if f.usingI2C {
return nil, errors.New("d2xx: already using I²C")
}
if f.usingSPI {
return nil, errors.New("d2xx: already using SPI")
}
if err := f.i.setupI2C(pull == gpio.PullUp); err != nil {
_ = f.i.stopI2C()
return nil, err
}
return &f.i, nil
}
// SPI returns a SPI port over the AD bus.
//
// It uses D0, D1, D2 and D3. D0 is the clock, D1 the output (MOSI), D2 is the
// input (MISO) and D3 is CS line.
func (f *FT232H) SPI() (spi.PortCloser, error) {
f.mu.Lock()
defer f.mu.Unlock()
if f.usingI2C {
return nil, errors.New("d2xx: already using I²C")
}
if f.usingSPI {
return nil, errors.New("d2xx: already using SPI")
}
// Don't mark it as being used yet. It only become used once Connect() is
// called.
return &f.s, nil
}
//
func newFT232R(g generic) (*FT232R, error) {
f := &FT232R{
generic: g,
dbus: [...]dbusPinSync{{num: 0}, {num: 1}, {num: 2}, {num: 3}, {num: 4}, {num: 5}, {num: 6}, {num: 7}},
cbus: [...]cbusPin{{num: 8, p: gpio.PullUp}, {num: 9, p: gpio.PullUp}, {num: 10, p: gpio.PullUp}, {num: 11, p: gpio.Float}},
}
// Use the UART names, as this is how all FT232R boards are marked.
dnames := [...]string{"TX", "RX", "RTS", "CTS", "DTR", "DSR", "DCD", "RI"}
for i := range f.dbus {
f.dbus[i].n = f.name + "." + dnames[i]
f.dbus[i].bus = f
f.hdr[i] = &f.dbus[i]
}
for i := range f.cbus {
f.cbus[i].n = f.name + ".C" + strconv.Itoa(i)
f.cbus[i].bus = f
f.hdr[i+8] = &f.cbus[i]
}
f.D0 = f.hdr[0]
f.D1 = f.hdr[1]
f.D2 = f.hdr[2]
f.D3 = f.hdr[3]
f.D4 = f.hdr[4]
f.D5 = f.hdr[5]
f.D6 = f.hdr[6]
f.D7 = f.hdr[7]
f.TX = f.hdr[0]
f.RX = f.hdr[1]
f.RTS = f.hdr[2]
f.CTS = f.hdr[3]
f.DTR = f.hdr[4]
f.DSR = f.hdr[5]
f.DCD = f.hdr[6]
f.RI = f.hdr[7]
f.C0 = f.hdr[8]
f.C1 = f.hdr[9]
f.C2 = f.hdr[10]
f.C3 = f.hdr[11]
// Default to 3MHz.
if err := f.h.SetBaudRate(3 * physic.MegaHertz); err != nil {
return nil, err
}
// Set all CBus pins as input.
if err := f.h.SetBitMode(0, bitModeCbusBitbang); err != nil {
return nil, err
}
// And read their value.
// TODO(maruel): Sadly this is impossible to know which pin is input or
// output, but we could try to guess, as the call above may generate noise on
// the line which could interfere with the device connected.
var err error
if f.cbusnibble, err = f.h.GetBitMode(); err != nil {
return nil, err
}
// Set all DBus as asynchronous bitbang, everything as input.
if err := f.h.SetBitMode(0, bitModeAsyncBitbang); err != nil {
return nil, err
}
// And read their value.
var b [1]byte
if _, err := f.h.ReadAll(context.Background(), b[:]); err != nil {
return nil, err
}
f.dvalue = b[0]
f.s.c.f = f
return f, nil
}
// FT232R represents a FT232RL/FT232RQ device.
//
// It implements Dev.
//
// Not all pins may be physically connected on the header!
//
// Adafruit's version only has the following pins connected: RX, TX, RTS and
// CTS.
//
// SparkFun's version exports all pins *except* (inexplicably) the CBus ones.
//
// The FT232R has 128 bytes output buffer and 256 bytes input buffer.
//
// Pin C4 can only be used in 'slow' mode via EEPROM and is currently not
// implemented.
//
// Datasheet
//
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf
type FT232R struct {
generic
// Pin and their alias to the Dn pins for user convenience. Each pair points
// to the exact same pin.
D0, TX gpio.PinIO // Transmit; SPI_MOSI
D1, RX gpio.PinIO // Receive; SPI_MISO
D2, RTS gpio.PinIO // Request To Send Control Output / Handshake signal; SPI_CLK
D3, CTS gpio.PinIO // Clear to Send Control input / Handshake signal; SPI_CS
D4, DTR gpio.PinIO // Data Terminal Ready Control Output / Handshake signal
D5, DSR gpio.PinIO // Data Set Ready Control Input / Handshake signal
D6, DCD gpio.PinIO // Data Carrier Detect Control input
D7, RI gpio.PinIO // Ring Indicator Control Input. When remote wake up is enabled in the internal EEPROM taking RI# low can be used to resume the PC USB host controller from suspend.
// The CBus pins are slower to use, but can drive an high load, like a LED.
C0 gpio.PinIO
C1 gpio.PinIO
C2 gpio.PinIO
C3 gpio.PinIO
dbus [8]dbusPinSync
cbus [4]cbusPin
hdr [12]gpio.PinIO
// Mutable.
mu sync.Mutex
usingSPI bool
usingCBus bool
s spiSyncPort
dmask uint8 // 0 input, 1 output
dvalue uint8
cbusnibble uint8 // upper nibble is I/O control, lower nibble is values.
}
// Header returns the GPIO pins exposed on the chip.
func (f *FT232R) Header() []gpio.PinIO {
out := make([]gpio.PinIO, len(f.hdr))
copy(out, f.hdr[:])
return out
}
// SetDBusMask sets all D0~D7 input or output mode at once.
//
// mask is the input/output pins to use. A bit value of 0 sets the
// corresponding pin to an input, a bit value of 1 sets the corresponding pin
// to an output.
//
// It should be called before calling Tx().
func (f *FT232R) SetDBusMask(mask uint8) error {
f.mu.Lock()
defer f.mu.Unlock()
if f.usingSPI {
return errors.New("d2xx: already using SPI")
}
return f.setDBusMaskLocked(mask)
}
// Tx does synchronized read-then-write on all the D0~D7 GPIOs.
//
// SetSpeed() determines the pace at which the I/O is done.
//
// SetDBusMask() determines which bits are interpreted in the w and r byte
// slice. w has its significant value masked by 'mask' and r has its
// significant value masked by '^mask'.
//
// Input sample is done *before* updating outputs. So r[0] is sampled before
// w[0] is used. The last w byte should be duplicated if an addition read is
// desired.
//
// On the Adafruit cable, only the first 4 bits D0(TX), D1(RX), D2(RTS) and
// D3(CTS) are connected. This is just enough to create a full duplex SPI bus!
func (f *FT232R) Tx(w, r []byte) error {
if len(w) != 0 {
if len(r) != 0 && len(w) != len(r) {
return errors.New("d2xx: length of buffer w and r must match")
}
} else if len(r) == 0 {
return errors.New("d2xx: at least one of w or r must be passed")
}
f.mu.Lock()
defer f.mu.Unlock()
if f.usingSPI {
return errors.New("d2xx: already using SPI")
}
return f.txLocked(w, r)
}
// SPI returns a SPI port over the first 4 pins.
//
// It uses D0(TX), D1(RX), D2(RTS) and D3(CTS). D2(RTS) is the clock, D0(TX)
// the output (MOSI), D1(RX) is the input (MISO) and D3(CTS) is CS line.
func (f *FT232R) SPI() (spi.PortCloser, error) {
f.mu.Lock()
defer f.mu.Unlock()
if f.usingSPI {
return nil, errors.New("d2xx: already using SPI")
}
// Don't mark it as being used yet. It only become used once Connect() is
// called.
return &f.s, nil
}
// setDBusMaskLocked is the locked version of SetDBusMask.
func (f *FT232R) setDBusMaskLocked(mask uint8) error {
if mask != f.dmask {
if err := f.h.SetBitMode(mask, bitModeAsyncBitbang); err != nil {
return err
}
f.dmask = mask
}
return nil
}
func (f *FT232R) txLocked(w, r []byte) error {
// Investigate FT232R clock issue:
// http://developer.intra2net.com/mailarchive/html/libftdi/2010/msg00240.html
// The FT232R has 128 bytes TX buffer and 256 bytes RX buffer. Chunk into 64
// bytes chunks. That's half the buffer size of the TX buffer and permits
// pipelining and removes the risk of buffer overrun. This is important
// otherwise there's huge gaps due to the USB transmit overhead.
// TODO(maruel): Determine what's optimal via experimentation.
chunk := 64
var scratch [128]byte
if len(w) == 0 {
// Read only.
for i := range scratch {
scratch[i] = f.dvalue
}
for len(r) != 0 {
// TODO(maruel): Optimize.
c := len(r)
if c > chunk {
c = chunk
}
if _, err := f.h.Write(scratch[:c]); err != nil {
return err
}
if _, err := f.h.ReadAll(context.Background(), r[:c]); err != nil {
return err
}
r = r[c:]
}
} else if len(r) == 0 {
// Write only.
// The first write is 128 bytes to fill the buffer.
chunk = 128
for len(w) != 0 {
c := len(w)
if c > chunk {
c = chunk
}
if _, err := f.h.Write(w[:c]); err != nil {
return err
}
w = w[c:]
chunk = 64
}
/*
// Let the USB drive pace it.
if _, err := f.h.Write(w); err != nil {
return err
}
*/
} else {
// R/W.
// Always write one 'w' ahead.
// The first write is 128 bytes to fill the buffer.
chunk = 128
cw := len(w)
if cw > chunk {
cw = chunk
}
if _, err := f.h.Write(w[:cw]); err != nil {
return err
}
w = w[cw:]
chunk = 64
for len(r) != 0 {
// Read then write.
cr := len(r)
if cr > chunk {
cr = chunk
}
if _, err := f.h.ReadAll(context.Background(), r[:cr]); err != nil {
return err
}
r = r[cr:]
cw = len(w)
if cw > chunk {
cw = chunk
}
if cw != 0 {
if _, err := f.h.Write(w[:cw]); err != nil {
return err
}
w = w[cw:]
}
}
}
return nil
}
// dbusSyncGPIOFunc implements dbusSync. It returns the function of a GPIO
// pin.
func (f *FT232R) dbusSyncGPIOFunc(n int) string {
f.mu.Lock()
defer f.mu.Unlock()
if f.usingSPI {
switch n {
case 0:
return "SPI_MOSI" // TX
case 1:
return "SPI_MISO" // RX
case 2:
return "SPI_CLK" // RTS
case 3:
return "SPI_CS" // CTS
}
}
mask := uint8(1 << uint(n))
if f.dmask&mask != 0 {
return "Out/" + gpio.Level(f.dvalue&mask != 0).String()
}
return "In/" + f.dbusSyncReadLocked(n).String()
}
// dbusSyncGPIOIn implements dbusSync.
func (f *FT232R) dbusSyncGPIOIn(n int) error {
f.mu.Lock()
defer f.mu.Unlock()
// TODO(maruel): if f.usingSPI && n < 4.
mask := uint8(1 << uint(n))
if f.dmask&mask == 0 {
// Already input.
return nil
}
v := f.dmask &^ mask
if err := f.h.SetBitMode(v, bitModeAsyncBitbang); err != nil {
return err
}
f.dmask = v
return nil
}
// dbusSyncGPIORead implements dbusSync.
func (f *FT232R) dbusSyncGPIORead(n int) gpio.Level {
f.mu.Lock()
defer f.mu.Unlock()
return f.dbusSyncReadLocked(n)
}
func (f *FT232R) dbusSyncReadLocked(n int) gpio.Level {
// In synchronous mode, to read we must write first to for a sample.
b := [1]byte{f.dvalue}
if _, err := f.h.Write(b[:]); err != nil {
return gpio.Low
}
mask := uint8(1 << uint(n))
if _, err := f.h.ReadAll(context.Background(), b[:]); err != nil {
return gpio.Low
}
f.dvalue = b[0]
return f.dvalue&mask != 0
}
// dbusSyncGPIOOut implements dbusSync.
func (f *FT232R) dbusSyncGPIOOut(n int, l gpio.Level) error {
f.mu.Lock()
defer f.mu.Unlock()
mask := uint8(1 << uint(n))
if f.dmask&mask != 1 {
// Was input.
v := f.dmask | mask
if err := f.h.SetBitMode(v, bitModeAsyncBitbang); err != nil {
return err
}
f.dmask = v
}
return f.dbusSyncGPIOOutLocked(n, l)
}
func (f *FT232R) dbusSyncGPIOOutLocked(n int, l gpio.Level) error {
b := [1]byte{f.dvalue}
if _, err := f.h.Write(b[:]); err != nil {
return err
}
f.dvalue = b[0]
// In synchronous mode, we must read after writing to flush the buffer.
if _, err := f.h.Write(b[:]); err != nil {
return err
}
return nil
}
// cBusGPIOFunc implements cBusGPIO.
func (f *FT232R) cBusGPIOFunc(n int) string {
f.mu.Lock()
defer f.mu.Unlock()
fmask := uint8(0x10 << uint(n))
vmask := uint8(1 << uint(n))
if f.cbusnibble&fmask != 0 {
return "Out/" + gpio.Level(f.cbusnibble&vmask != 0).String()
}
return "In/" + f.cBusReadLocked(n).String()
}
// cBusGPIOIn implements cBusGPIO.
func (f *FT232R) cBusGPIOIn(n int) error {
f.mu.Lock()
defer f.mu.Unlock()
fmask := uint8(0x10 << uint(n))
if f.cbusnibble&fmask == 0 {
// Already input.
return nil
}
v := f.cbusnibble &^ fmask
if err := f.h.SetBitMode(v, bitModeCbusBitbang); err != nil {
return err
}
f.cbusnibble = v
return nil
}
// cBusGPIORead implements cBusGPIO.
func (f *FT232R) cBusGPIORead(n int) gpio.Level {
f.mu.Lock()
defer f.mu.Unlock()
return f.cBusReadLocked(n)
}
func (f *FT232R) cBusReadLocked(n int) gpio.Level {
v, err := f.h.GetBitMode()
if err != nil {
return gpio.Low
}
f.cbusnibble = v
vmask := uint8(1 << uint(n))
return f.cbusnibble&vmask != 0
}
// cBusGPIOOut implements cBusGPIO.
func (f *FT232R) cBusGPIOOut(n int, l gpio.Level) error {
f.mu.Lock()
defer f.mu.Unlock()
fmask := uint8(0x10 << uint(n))
vmask := uint8(1 << uint(n))
v := f.cbusnibble | fmask
if l {
v |= vmask
} else {
v &^= vmask
}
if f.cbusnibble == v {
// Was already in the right mode.
return nil
}
if err := f.h.SetBitMode(v, bitModeCbusBitbang); err != nil {
return err
}
f.cbusnibble = v
return nil
}
//
var _ conn.Resource = Dev(nil)

20
vendor/periph.io/x/host/v3/ftdi/doc.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// 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 ftdi implements support for popular FTDI devices.
//
// The supported devices (FT232h/FT232r) implement support for various
// protocols like the GPIO, I²C, SPI, UART, JTAG.
//
// More details
//
// See https://periph.io/device/ftdi/ for more details, and how to configure
// the host to be able to use this driver.
//
// Datasheets
//
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf
//
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf
package ftdi

213
vendor/periph.io/x/host/v3/ftdi/driver.go generated vendored Normal file
View File

@ -0,0 +1,213 @@
// 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 ftdi
import (
"strconv"
"sync"
"periph.io/x/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/i2c/i2creg"
"periph.io/x/conn/v3/pin"
"periph.io/x/conn/v3/pin/pinreg"
"periph.io/x/conn/v3/spi/spireg"
"periph.io/x/d2xx"
)
// All enumerates all the connected FTDI devices.
func All() []Dev {
drv.mu.Lock()
defer drv.mu.Unlock()
out := make([]Dev, len(drv.all))
copy(out, drv.all)
return out
}
//
// open opens a FTDI device.
//
// Must be called with mu held.
func open(opener func(i int) (d2xx.Handle, d2xx.Err), i int) (Dev, error) {
h, err := openHandle(opener, i)
if err != nil {
return nil, err
}
if err := h.Init(); err != nil {
// setupCommon() takes the device in its previous state. It could be in an
// unexpected state, so try resetting it first.
if err := h.Reset(); err != nil {
_ = h.Close()
return nil, err
}
if err := h.Init(); err != nil {
_ = h.Close()
return nil, err
}
// The second attempt worked.
}
// Makes a copy of the handle.
g := generic{index: i, h: h, name: h.t.String()}
if i > 0 {
// When more than one device is present, add "(index)" suffix.
// TODO(maruel): Using the serial number would be nicer than a number.
g.name += "(" + strconv.Itoa(i) + ")"
}
// Makes a copy of the generic instance.
switch g.h.t {
case DevTypeFT232H:
f, err := newFT232H(g)
if err != nil {
_ = h.Close()
return nil, err
}
return f, nil
case DevTypeFT2232H:
f, err := newFT232H(g)
if err != nil {
_ = h.Close()
return nil, err
}
return f, nil
case DevTypeFT232R:
f, err := newFT232R(g)
if err != nil {
_ = h.Close()
return nil, err
}
return f, nil
default:
return &g, nil
}
}
// registerDev registers the header and supported buses and ports in the
// relevant registries.
func registerDev(d Dev, multi bool) error {
name := d.String()
hdr := d.Header()
// Register the GPIOs.
for _, p := range hdr {
if err := gpioreg.Register(p); err != nil {
return err
}
}
if !multi {
// Register shorthands.
// The "." used here vs the "_" used in pinreg is unfortunate. Investigate
// a better way.
prefix := len(name) + 1
for _, p := range hdr {
n := p.Name()
if err := gpioreg.RegisterAlias(n[prefix:], n); err != nil {
return err
}
}
}
// Register the header.
raw := make([][]pin.Pin, len(hdr))
for i := range hdr {
raw[i] = []pin.Pin{hdr[i]}
}
if err := pinreg.Register(name, raw); err != nil {
return err
}
switch t := d.(type) {
case *FT232H:
// Register I²C without pull up.
if err := i2creg.Register(name, nil, -1, func() (i2c.BusCloser, error) { return t.I2C(gpio.Float) }); err != nil {
return err
}
if err := spireg.Register(name, nil, -1, t.SPI); err != nil {
return err
}
// TODO(maruel): UART
case *FT232R:
// TODO(maruel): SPI, UART
}
return nil
}
// driver implements driver.Impl.
type driver struct {
mu sync.Mutex
all []Dev
d2xxOpen func(i int) (d2xx.Handle, d2xx.Err)
numDevices func() (int, error)
}
func (d *driver) String() string {
return "ftdi"
}
func (d *driver) Prerequisites() []string {
return nil
}
func (d *driver) After() []string {
return nil
}
func (d *driver) Init() (bool, error) {
num, err := d.numDevices()
if err != nil {
return true, err
}
multi := num > 1
for i := 0; i < num; i++ {
// TODO(maruel): Close the device one day. :)
if dev, err1 := open(d.d2xxOpen, i); err1 == nil {
d.all = append(d.all, dev)
if err = registerDev(dev, multi); err != nil {
return true, err
}
} else {
// Create a shallow broken handle, so the user can learn how to fix the
// problem.
//
// TODO(maruel): On macOS with a FT232R, calling two processes in a row
// often results in a broken device on the second process. Figure out why
// and make it more resilient.
err = err1
// The serial number is not available so what can be listed is limited.
// TODO(maruel): Add VID/PID?
name := "broken#" + strconv.Itoa(i) + ": " + err.Error()
d.all = append(d.all, &broken{index: i, err: err, name: name})
}
}
return true, err
}
func (d *driver) reset() {
d.mu.Lock()
defer d.mu.Unlock()
d.all = nil
// open is mocked in tests.
d.d2xxOpen = d2xx.Open
// numDevices is mocked in tests.
d.numDevices = numDevices
// The d2xx can hang for up to the timeout under certain circumstances and the
// Go profiler is not very useful to find the source, so use manual logging
// to see where time it spent.
//d.d2xxOpen = func(i int) (d2xx.Handle, int) {
// h, e := d2xxOpen(i)
// return &d2xxLoggingHandle{h}, e
//}
}
func init() {
if d2xx.Available {
drv.reset()
driverreg.MustRegister(&drv)
}
}
var drv driver

368
vendor/periph.io/x/host/v3/ftdi/eeprom.go generated vendored Normal file
View File

@ -0,0 +1,368 @@
// 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 ftdi
import (
"errors"
"fmt"
"unsafe"
)
// EEPROM is the unprocessed EEPROM content.
//
// The EEPROM is in 3 parts: the defined struct, the 4 strings and the rest
// which is used as an 'user area'. The size of the user area depends on the
// length of the strings. The user area content is not included in this struct.
type EEPROM struct {
// Raw is the raw EEPROM content. It excludes the strings.
Raw []byte
// The following condition must be true: len(Manufacturer) + len(Desc) <= 40.
Manufacturer string
ManufacturerID string
Desc string
Serial string
}
// Validate checks that the data is good.
func (e *EEPROM) Validate() error {
// Verify that the values are set correctly.
if len(e.Manufacturer) > 40 {
return errors.New("ftdi: Manufacturer is too long")
}
if len(e.ManufacturerID) > 40 {
return errors.New("ftdi: ManufacturerID is too long")
}
if len(e.Desc) > 40 {
return errors.New("ftdi: Desc is too long")
}
if len(e.Serial) > 40 {
return errors.New("ftdi: Serial is too long")
}
if len(e.Manufacturer)+len(e.Desc) > 40 {
return errors.New("ftdi: length of Manufacturer plus Desc is too long")
}
return nil
}
func (e *EEPROM) AsHeader() *EEPROMHeader {
// sizeof(EEPROMHeader)
if len(e.Raw) < 16 {
return nil
}
return (*EEPROMHeader)(unsafe.Pointer(&e.Raw[0]))
}
// AsFT232H returns the Raw data aliased as EEPROMFT232H.
func (e *EEPROM) AsFT232H() *EEPROMFT232H {
// sizeof(EEPROMFT232H)
if len(e.Raw) < 44 {
return nil
}
return (*EEPROMFT232H)(unsafe.Pointer(&e.Raw[0]))
}
// AsFT2232H returns the Raw data aliased as EEPROMFT2232H.
func (e *EEPROM) AsFT2232H() *EEPROMFT2232H {
// sizeof(EEPROMFT2232H)
if len(e.Raw) < 40 {
return nil
}
return (*EEPROMFT2232H)(unsafe.Pointer(&e.Raw[0]))
}
// AsFT232R returns the Raw data aliased as EEPROMFT232R.
func (e *EEPROM) AsFT232R() *EEPROMFT232R {
// sizeof(EEPROMFT232R)
if len(e.Raw) < 32 {
return nil
}
return (*EEPROMFT232R)(unsafe.Pointer(&e.Raw[0]))
}
// FT232hCBusMux is stored in the FT232H EEPROM to control each CBus pin.
type FT232hCBusMux uint8
const (
// TriSt-PU; Sets in Tristate (pull up) (C0~C6, C8, C9) on 75kΩ.
FT232hCBusTristatePullUp FT232hCBusMux = 0x00
// TXLED#; Pulses low when transmitting data (C0~C6, C8, C9).
FT232hCBusTxLED FT232hCBusMux = 0x01
// RXLED#; Pulses low when receiving data (C0~C6, C8, C9).
FT232hCBusRxLED FT232hCBusMux = 0x02
// TX&RXLED#; Pulses low when either receiving or transmitting data (C0~C6,
// C8, C9).
FT232hCBusTxRxLED FT232hCBusMux = 0x03
// PWREN#; Output is low after the device has been configured by USB, then
// high during USB suspend mode (C0~C6, C8, C9).
//
// Must be used with an external 10kΩ pull up.
FT232hCBusPwrEnable FT232hCBusMux = 0x04
// SLEEP#; Goes low during USB suspend mode (C0~C6, C8, C9).
FT232hCBusSleep FT232hCBusMux = 0x05
// DRIVE1; Drives pin to logic 0 (C0~C6, C8, C9).
FT232hCBusDrive0 FT232hCBusMux = 0x06
// DRIVE1; Drives pin to logic 1 (C0, C5, C6, C8, C9).
FT232hCBusDrive1 FT232hCBusMux = 0x07
// I/O Mode; CBus bit-bang mode option (C5, C6, C8, C9).
FT232hCBusIOMode FT232hCBusMux = 0x08
// TXDEN; Tx Data Enable. Used with RS485 level converters to enable the line
// driver during data transmit. It is active one bit time before the start
// bit up to until the end of the stop bit (C0~C6, C8, C9).
FT232hCBusTxdEnable FT232hCBusMux = 0x09
// CLK30 30MHz clock output (C0, C5, C6, C8, C9).
FT232hCBusClk30 FT232hCBusMux = 0x0A
// CLK15 15MHz clock output (C0, C5, C6, C8, C9).
FT232hCBusClk15 FT232hCBusMux = 0x0B
// CLK7.5 7.5MHz clock output (C0, C5, C6, C8, C9).
FT232hCBusClk7_5 FT232hCBusMux = 0x0C
)
const ft232hCBusMuxName = "FT232hCBusTristatePullUpFT232hCBusTxLEDFT232hCBusRxLEDFT232hCBusTxRxLEDFT232hCBusPwrEnableFT232hCBusSleepFT232hCBusDrive0FT232hCBusDrive1FT232hCBusIOModeFT232hCBusTxdEnableFT232hCBusClk30FT232hCBusClk15FT232hCBusClk7_5"
var fr232hCBusMuxIndex = [...]uint8{0, 24, 39, 54, 71, 90, 105, 121, 137, 153, 172, 187, 202, 218}
func (f FT232hCBusMux) String() string {
if f >= FT232hCBusMux(len(fr232hCBusMuxIndex)-1) {
return fmt.Sprintf("FT232hCBusMux(%d)", f)
}
return ft232hCBusMuxName[fr232hCBusMuxIndex[f]:fr232hCBusMuxIndex[f+1]]
}
// FT232rCBusMux is stored in the FT232R EEPROM to control each CBus pin.
type FT232rCBusMux uint8
const (
// TXDEN; Tx Data Enable. Used with RS485 level converters to enable the line
// driver during data transmit. It is active one bit time before the start
// bit up to until the end of the stop bit (C0~C4).
FT232rCBusTxdEnable FT232rCBusMux = 0x00
// PWREN#; Output is low after the device has been configured by USB, then
// high during USB suspend mode (C0~C4).
//
// Must be used with an external 10kΩ pull up.
FT232rCBusPwrEnable FT232rCBusMux = 0x01
// RXLED#; Pulses low when receiving data (C0~C4).
FT232rCBusRxLED FT232rCBusMux = 0x02
// TXLED#; Pulses low when transmitting data (C0~C4).
FT232rCBusTxLED FT232rCBusMux = 0x03
// TX&RXLED#; Pulses low when either receiving or transmitting data (C0~C4).
FT232rCBusTxRxLED FT232rCBusMux = 0x04
// SLEEP# Goes low during USB suspend mode (C0~C4).
FT232rCBusSleep FT232rCBusMux = 0x05
// CLK48 48Mhz +/-0.7% clock output (C0~C4).
FT232rCBusClk48 FT232rCBusMux = 0x06
// CLK24 24Mhz clock output (C0~C4).
FT232rCBusClk24 FT232rCBusMux = 0x07
// CLK12 12Mhz clock output (C0~C4).
FT232rCBusClk12 FT232rCBusMux = 0x08
// CLK6 6Mhz +/-0.7% clock output (C0~C4).
FT232rCBusClk6 FT232rCBusMux = 0x09
// CBitBangI/O; CBus bit-bang mode option (C0~C3).
FT232rCBusIOMode FT232rCBusMux = 0x0A
// BitBangWRn; CBus WR# strobe output (C0~C3).
FT232rCBusBitBangWR FT232rCBusMux = 0x0B
// BitBangRDn; CBus RD# strobe output (C0~C3).
FT232rCBusBitBangRD FT232rCBusMux = 0x0C
)
const ft232rCBusMuxName = "FT232rCBusTxdEnableFT232rCBusPwrEnableFT232rCBusRxLEDFT232rCBusTxLEDFT232rCBusTxRxLEDFT232rCBusSleepFT232rCBusClk48FT232rCBusClk24FT232rCBusClk12FT232rCBusClk6FT232rCBusIOModeFT232rCBusBitBangWRFT232rCBusBitBangRD"
var ft232rCBusMuxIndex = [...]uint8{0, 19, 38, 53, 68, 85, 100, 115, 130, 145, 159, 175, 194, 213}
func (f FT232rCBusMux) String() string {
if f >= FT232rCBusMux(len(ft232rCBusMuxIndex)-1) {
return fmt.Sprintf("FT232rCBusMux(%d)", f)
}
return ft232rCBusMuxName[ft232rCBusMuxIndex[f]:ft232rCBusMuxIndex[f+1]]
}
// EEPROMHeader is the common header found on FTDI devices.
//
// It is 16 bytes long.
type EEPROMHeader struct {
DeviceType DevType // 0x00 FTxxxx device type to be programmed
VendorID uint16 // 0x04 Defaults to 0x0403; can be changed
ProductID uint16 // 0x06 Defaults to 0x6001 for FT232R, 0x6014 for FT232H, relevant value
SerNumEnable uint8 // 0x07 bool Non-zero if serial number to be used
Unused0 uint8 // 0x08 For alignment.
MaxPower uint16 // 0x0A 0mA < MaxPower <= 500mA
SelfPowered uint8 // 0x0C bool 0 = bus powered, 1 = self powered
RemoteWakeup uint8 // 0x0D bool 0 = not capable, 1 = capable; RI# low will wake host in 20ms.
PullDownEnable uint8 // 0x0E bool Non zero if pull down in suspend enabled
Unused1 uint8 // 0x0F For alignment.
}
// EEPROMFT232H is the EEPROM layout of a FT232H device.
//
// It is 44 bytes long.
type EEPROMFT232H struct {
EEPROMHeader
// FT232H specific.
ACSlowSlew uint8 // 0x10 bool Non-zero if AC bus pins have slow slew
ACSchmittInput uint8 // 0x11 bool Non-zero if AC bus pins are Schmitt input
ACDriveCurrent uint8 // 0x12 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
ADSlowSlew uint8 // 0x13 bool Non-zero if AD bus pins have slow slew
ADSchmittInput uint8 // 0x14 bool Non-zero if AD bus pins are Schmitt input
ADDriveCurrent uint8 // 0x15 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
Cbus0 FT232hCBusMux // 0x16
Cbus1 FT232hCBusMux // 0x17
Cbus2 FT232hCBusMux // 0x18
Cbus3 FT232hCBusMux // 0x19
Cbus4 FT232hCBusMux // 0x1A
Cbus5 FT232hCBusMux // 0x1B
Cbus6 FT232hCBusMux // 0x1C
Cbus7 FT232hCBusMux // 0x1D C7 is limited a sit can only do 'suspend on C7 low'. Defaults pull down.
Cbus8 FT232hCBusMux // 0x1E
Cbus9 FT232hCBusMux // 0x1F
FT1248Cpol uint8 // 0x20 bool FT1248 clock polarity - clock idle high (true) or clock idle low (false)
FT1248Lsb uint8 // 0x21 bool FT1248 data is LSB (true), or MSB (false)
FT1248FlowControl uint8 // 0x22 bool FT1248 flow control enable
IsFifo uint8 // 0x23 bool Non-zero if Interface is 245 FIFO
IsFifoTar uint8 // 0x24 bool Non-zero if Interface is 245 FIFO CPU target
IsFastSer uint8 // 0x25 bool Non-zero if Interface is Fast serial
IsFT1248 uint8 // 0x26 bool Non-zero if Interface is FT1248
PowerSaveEnable uint8 // 0x27 bool Suspect on ACBus7 low.
DriverType uint8 // 0x28 bool 0 is D2XX, 1 is VCP
Unused2 uint8 // 0x29
Unused3 uint16 // 0x30
}
func (e *EEPROMFT232H) Defaults() {
// As found on Adafruit device.
e.ACDriveCurrent = 4
e.ADDriveCurrent = 4
e.Cbus0 = FT232hCBusTristatePullUp
e.Cbus1 = FT232hCBusTristatePullUp
e.Cbus2 = FT232hCBusTristatePullUp
e.Cbus3 = FT232hCBusTristatePullUp
e.Cbus4 = FT232hCBusTristatePullUp
e.Cbus5 = FT232hCBusTristatePullUp
e.Cbus6 = FT232hCBusTristatePullUp
e.Cbus7 = FT232hCBusTristatePullUp
e.Cbus8 = FT232hCBusDrive1
e.Cbus9 = FT232hCBusDrive0
}
// EEPROMFT2232H is the EEPROM layout of a FT2232H device.
//
// It is 40 bytes long.
type EEPROMFT2232H struct {
EEPROMHeader
// FT232H specific.
ALSlowSlew uint8 // 0x10 bool non-zero if AL pins have slow slew
ALSchmittInput uint8 // 0x11 bool non-zero if AL pins are Schmitt input
ALDriveCurrent uint8 // 0x12 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
AHSlowSlew uint8 // 0x13 bool non-zero if AH pins have slow slew
AHSchmittInput uint8 // 0x14 bool non-zero if AH pins are Schmitt input
AHDriveCurrent uint8 // 0x15 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
BLSlowSlew uint8 // 0x16 bool non-zero if BL pins have slow slew
BLSchmittInput uint8 // 0x17 bool non-zero if BL pins are Schmitt input
BLDriveCurrent uint8 // 0x18 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
BHSlowSlew uint8 // 0x19 bool non-zero if BH pins have slow slew
BHSchmittInput uint8 // 0x1A bool non-zero if BH pins are Schmitt input
BHDriveCurrent uint8 // 0x1B Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
AIsFifo uint8 // 0x1C bool non-zero if interface is 245 FIFO
AIsFifoTar uint8 // 0x1D bool non-zero if interface is 245 FIFO CPU target
AIsFastSer uint8 // 0x1E bool non-zero if interface is Fast serial
BIsFifo uint8 // 0x1F bool non-zero if interface is 245 FIFO
BIsFifoTar uint8 // 0x20 bool non-zero if interface is 245 FIFO CPU target
BIsFastSer uint8 // 0x21 bool non-zero if interface is Fast serial
PowerSaveEnable uint8 // 0x22 bool non-zero if using BCBUS7 to save power for self-powered designs
ADriverType uint8 // 0x23 bool
BDriverType uint8 // 0x24 bool
Unused2 uint8 // 0x25
Unused3 uint16 // 0x26
}
// EEPROMFT232R is the EEPROM layout of a FT232R device.
//
// It is 32 bytes long.
type EEPROMFT232R struct {
EEPROMHeader
// FT232R specific.
IsHighCurrent uint8 // 0x10 bool High Drive I/Os; 3mA instead of 1mA (@3.3V)
UseExtOsc uint8 // 0x11 bool Use external oscillator
InvertTXD uint8 // 0x12 bool
InvertRXD uint8 // 0x13 bool
InvertRTS uint8 // 0x14 bool
InvertCTS uint8 // 0x15 bool
InvertDTR uint8 // 0x16 bool
InvertDSR uint8 // 0x17 bool
InvertDCD uint8 // 0x18 bool
InvertRI uint8 // 0x19 bool
Cbus0 FT232rCBusMux // 0x1A Default ft232rCBusTxLED
Cbus1 FT232rCBusMux // 0x1B Default ft232rCBusRxLED
Cbus2 FT232rCBusMux // 0x1C Default ft232rCBusTxdEnable
Cbus3 FT232rCBusMux // 0x1D Default ft232rCBusPwrEnable
Cbus4 FT232rCBusMux // 0x1E Default ft232rCBusSleep
DriverType uint8 // 0x1F bool 0 is D2XX, 1 is VCP
}
func (e *EEPROMFT232R) Defaults() {
// As found on Adafruit device.
e.Cbus0 = FT232rCBusTxLED
e.Cbus1 = FT232rCBusRxLED
e.Cbus2 = FT232rCBusTxdEnable
e.Cbus3 = FT232rCBusPwrEnable
e.Cbus4 = FT232rCBusSleep
e.DriverType = 1
}
//
// DevType is the FTDI device type.
type DevType uint32
const (
DevTypeFTBM DevType = iota // 0
DevTypeFTAM
DevTypeFT100AX
DevTypeUnknown // 3
DevTypeFT2232C
DevTypeFT232R // 5
DevTypeFT2232H
DevTypeFT4232H
DevTypeFT232H // 8
DevTypeFTXSeries
DevTypeFT4222H0
DevTypeFT4222H1_2
DevTypeFT4222H3
DevTypeFT4222Prog
DevTypeFT900
DevTypeFT930
DevTypeFTUMFTPD3A
)
// EEPROMSize returns the size of the EEPROM for this device.
func (d DevType) EEPROMSize() int {
switch d {
case DevTypeFT232H:
// sizeof(EEPROMFT232H)
return 44
case DevTypeFT2232H:
// sizeof(EEPROMFT2232H)
return 40
case DevTypeFT232R:
// sizeof(EEPROMFT232R)
return 32
default:
return 256
}
}
const devTypeName = "FTBMFTAMFT100AXUnknownFT2232CFT232RFT2232HFT4232HFT232HFTXSeriesFT4222H0FT4222H1/2FT4222H3FT4222ProgFT900FT930FTUMFTPD3A"
var devTypeIndex = [...]uint8{0, 4, 8, 15, 22, 29, 35, 42, 49, 55, 64, 72, 82, 90, 100, 105, 110, 120}
func (d DevType) String() string {
if d >= DevType(len(devTypeIndex)-1) {
d = DevTypeUnknown
}
return devTypeName[devTypeIndex[d]:devTypeIndex[d+1]]
}

5
vendor/periph.io/x/host/v3/ftdi/ftdi.go generated vendored Normal file
View File

@ -0,0 +1,5 @@
// 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.
package ftdi

241
vendor/periph.io/x/host/v3/ftdi/gpio.go generated vendored Normal file
View File

@ -0,0 +1,241 @@
// 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.
// Emulate independent GPIOs.
package ftdi
import (
"errors"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
// dbusSync is the handler of a synchronous bitbang on DBus.
//
// More details at:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_232R-01_Bit_Bang_Mode_Available_For_FT232R_and_Ft245R.pdf
type dbusSync interface {
dbusSyncGPIOFunc(n int) string
dbusSyncGPIOIn(n int) error
dbusSyncGPIORead(n int) gpio.Level
dbusSyncGPIOOut(n int, l gpio.Level) error
}
// dbusPinSync represents a GPIO on a synchronous bitbang DBus.
//
// It is immutable and stateless.
type dbusPinSync struct {
n string
num int
bus dbusSync
}
// String implements conn.Resource.
func (s *dbusPinSync) String() string {
return s.n
}
// Halt implements conn.Resource.
func (s *dbusPinSync) Halt() error {
return nil
}
// Name implements pin.Pin.
func (s *dbusPinSync) Name() string {
return s.n
}
// Number implements pin.Pin.
func (s *dbusPinSync) Number() int {
return s.num
}
// Function implements pin.Pin.
func (s *dbusPinSync) Function() string {
return s.bus.dbusSyncGPIOFunc(s.num)
}
// In implements gpio.PinIn.
func (s *dbusPinSync) In(pull gpio.Pull, e gpio.Edge) error {
if e != gpio.NoEdge {
// We could support it on D5.
return errors.New("d2xx: edge triggering is not supported")
}
if pull != gpio.PullUp && pull != gpio.PullNoChange {
// EEPROM has a PullDownEnable flag.
return errors.New("d2xx: pull is not supported")
}
return s.bus.dbusSyncGPIOIn(s.num)
}
// Read implements gpio.PinIn.
func (s *dbusPinSync) Read() gpio.Level {
return s.bus.dbusSyncGPIORead(s.num)
}
// WaitForEdge implements gpio.PinIn.
func (s *dbusPinSync) WaitForEdge(t time.Duration) bool {
return false
}
// DefaultPull implements gpio.PinIn.
func (s *dbusPinSync) DefaultPull() gpio.Pull {
// 200kΩ
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf
// p. 24
return gpio.PullUp
}
// Pull implements gpio.PinIn.
func (s *dbusPinSync) Pull() gpio.Pull {
return gpio.PullUp
}
// Out implements gpio.PinOut.
func (s *dbusPinSync) Out(l gpio.Level) error {
return s.bus.dbusSyncGPIOOut(s.num, l)
}
// PWM implements gpio.PinOut.
func (s *dbusPinSync) PWM(d gpio.Duty, f physic.Frequency) error {
return errors.New("d2xx: not implemented")
}
/*
func (s *dbusPinSync) Drive() physic.ElectricCurrent {
// optionally 3
//return s.bus.ee.DDriveCurrent * physic.MilliAmpere
return physic.MilliAmpere
}
func (s *dbusPinSync) SlewLimit() bool {
//return s.bus.ee.DSlowSlew
return false
}
func (s *dbusPinSync) Hysteresis() bool {
//return s.bus.ee.DSchmittInput
return true
}
*/
//
// cBusGPIO is the handler of a CBus bitbang bus.
//
// This is an asynchronous mode.
//
// More details at:
// http://www.ftdichip.com/Support/Knowledgebase/index.html?cbusbitbangmode.htm
type cBusGPIO interface {
cBusGPIOFunc(n int) string
cBusGPIOIn(n int) error
cBusGPIORead(n int) gpio.Level
cBusGPIOOut(n int, l gpio.Level) error
}
// cbusPin represents a GPIO on a CBus bitbang bus.
//
// It is immutable and stateless.
type cbusPin struct {
n string
num int
p gpio.Pull
bus cBusGPIO
}
// String implements conn.Resource.
func (c *cbusPin) String() string {
return c.n
}
// Halt implements conn.Resource.
func (c *cbusPin) Halt() error {
return nil
}
// Name implements pin.Pin.
func (c *cbusPin) Name() string {
return c.n
}
// Number implements pin.Pin.
func (c *cbusPin) Number() int {
return c.num
}
// Function implements pin.Pin.
func (c *cbusPin) Function() string {
return c.bus.cBusGPIOFunc(c.num)
}
// In implements gpio.PinIn.
func (c *cbusPin) In(pull gpio.Pull, e gpio.Edge) error {
if e != gpio.NoEdge {
// We could support it on D5.
return errors.New("d2xx: edge triggering is not supported")
}
if pull != c.p && pull != gpio.PullNoChange {
// EEPROM has a PullDownEnable flag.
return errors.New("d2xx: pull is not supported")
}
return c.bus.cBusGPIOIn(c.num)
}
// Read implements gpio.PinIn.
func (c *cbusPin) Read() gpio.Level {
return c.bus.cBusGPIORead(c.num)
}
// WaitForEdge implements gpio.PinIn.
func (c *cbusPin) WaitForEdge(t time.Duration) bool {
return false
}
// DefaultPull implements gpio.PinIn.
func (c *cbusPin) DefaultPull() gpio.Pull {
// 200kΩ
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf
// p. 24
return c.p
}
// Pull implements gpio.PinIn.
func (c *cbusPin) Pull() gpio.Pull {
return c.p
}
// Out implements gpio.PinOut.
func (c *cbusPin) Out(l gpio.Level) error {
return c.bus.cBusGPIOOut(c.num, l)
}
// PWM implements gpio.PinOut.
func (c *cbusPin) PWM(d gpio.Duty, f physic.Frequency) error {
return errors.New("d2xx: not implemented")
}
/*
func (c *cbusPin) Drive() physic.ElectricCurrent {
// optionally 3
//return c.bus.ee.CDriveCurrent * physic.MilliAmpere
return physic.MilliAmpere
}
func (c *cbusPin) SlewLimit() bool {
//return c.bus.ee.CSlowSlew
return false
}
func (c *cbusPin) Hysteresis() bool {
//return c.bus.ee.CSchmittInput
return true
}
*/
var _ gpio.PinIO = &dbusPinSync{}
var _ gpio.PinIO = &cbusPin{}

382
vendor/periph.io/x/host/v3/ftdi/handle.go generated vendored Normal file
View File

@ -0,0 +1,382 @@
// 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.
package ftdi
import (
"context"
"errors"
"fmt"
"io"
"periph.io/x/conn/v3/physic"
"periph.io/x/d2xx"
)
//
// bitMode is used by SetBitMode to change the chip behavior.
type bitMode uint8
const (
// Resets all Pins to their default value
bitModeReset bitMode = 0x00
// Sets the DBus to asynchronous bit-bang.
bitModeAsyncBitbang bitMode = 0x01
// Switch to MPSSE mode (FT2232, FT2232H, FT4232H and FT232H).
bitModeMpsse bitMode = 0x02
// Sets the DBus to synchronous bit-bang (FT232R, FT245R, FT2232, FT2232H,
// FT4232H and FT232H).
bitModeSyncBitbang bitMode = 0x04
// Switch to MCU host bus emulation (FT2232, FT2232H, FT4232H and FT232H).
bitModeMcuHost bitMode = 0x08
// Switch to fast opto-isolated serial mode (FT2232, FT2232H, FT4232H and
// FT232H).
bitModeFastSerial bitMode = 0x10
// Sets the CBus in 4 bits bit-bang mode (FT232R and FT232H)
// In this case, upper nibble controls which pin is output/input, lower
// controls which of outputs are high and low.
bitModeCbusBitbang bitMode = 0x20
// Single Channel Synchronous 245 FIFO mode (FT2232H and FT232H).
bitModeSyncFifo bitMode = 0x40
)
// numDevices returns the number of detected devices.
func numDevices() (int, error) {
num, e := d2xx.CreateDeviceInfoList()
if e != 0 {
return 0, toErr("GetNumDevices initialization failed", e)
}
return num, nil
}
func openHandle(opener func(i int) (d2xx.Handle, d2xx.Err), i int) (*handle, error) {
h, e := opener(i)
if e != 0 {
return nil, toErr("Open", e)
}
d := &handle{h: h}
t, vid, did, e := h.GetDeviceInfo()
if e != 0 {
_ = d.Close()
return nil, toErr("GetDeviceInfo", e)
}
d.t = DevType(t)
d.venID = vid
d.devID = did
return d, nil
}
// handle is a thin wrapper around the low level d2xx device handle to make it
// more go-idiomatic.
//
// It also implements many utility functions to help with initialization and
// device management.
type handle struct {
// It is just above 'handle' which directly maps to D2XX function calls.
//
// Dev converts the int error type into Go native error and handles higher
// level functionality like reading and writing to the USB connection.
//
// The content of the struct is immutable after initialization.
h d2xx.Handle
t DevType
venID uint16
devID uint16
}
func (h *handle) Close() error {
// Not yet called.
return toErr("Close", h.h.Close())
}
// Init is the general setup for common devices.
//
// It tries first the 'happy path' which doesn't reset the device. By doing so,
// the goal is to reduce the amount of glitches on the GPIO pins, on a best
// effort basis. On all devices, the GPIOs are still reset as inputs, since
// there is no way to determine if each GPIO is an input or output.
func (h *handle) Init() error {
// Driver: maximum packet size. Note that this clears any data in the buffer,
// so it is good to do it immediately after a reset. The 'out' parameter is
// ignored.
// TODO(maruel): The FT232H doc claims a 512 byte packets support in hi-speed
// mode, which means that this would likely be better to use this value.
if e := h.h.SetUSBParameters(65536, 0); e != 0 {
return toErr("SetUSBParameters", e)
}
// Driver: Set I/O timeouts to 15 sec. The reason is that we want the
// timeouts to be very visible, at least as the driver is being developed.
if e := h.h.SetTimeouts(15000, 15000); e != 0 {
return toErr("SetTimeouts", e)
}
// Not sure: Disable event/error characters.
if e := h.h.SetChars(0, false, 0, false); e != 0 {
return toErr("SetChars", e)
}
// Not sure: Latency timer at 1ms.
if e := h.h.SetLatencyTimer(1); e != 0 {
return toErr("SetLatencyTimer", e)
}
// Not sure: Turn on flow control to synchronize IN requests.
if e := h.h.SetFlowControl(); e != 0 {
return toErr("SetFlowControl", e)
}
// Just in case. It's a very small cost.
return h.Flush()
}
// Reset resets the device.
func (h *handle) Reset() error {
if e := h.h.ResetDevice(); e != 0 {
return toErr("Reset", e)
}
if err := h.SetBitMode(0, bitModeReset); err != nil {
return err
}
// USB/driver: Flush any pending read buffer that had been sent by the device
// before it reset. Do not return any error there, as the device may spew a
// read error right after being initialized.
_ = h.Flush()
return nil
}
// GetBitMode returns the current bit mode.
//
// This is device-dependent.
func (h *handle) GetBitMode() (byte, error) {
l, e := h.h.GetBitMode()
if e != 0 {
return 0, toErr("GetBitMode", e)
}
return l, nil
}
// SetBitMode change the mode of operation of the device.
//
// mask sets which pins are inputs and outputs for bitModeCbusBitbang.
func (h *handle) SetBitMode(mask byte, mode bitMode) error {
return toErr("SetBitMode", h.h.SetBitMode(mask, byte(mode)))
}
// Flush flushes any data left in the read buffer.
func (h *handle) Flush() error {
var buf [128]byte
for {
p, err := h.Read(buf[:])
if err != nil {
return err
}
if p == 0 {
return nil
}
}
}
// Read returns as much as available in the read buffer without blocking.
func (h *handle) Read(b []byte) (int, error) {
// GetQueueStatus() 60µs is relatively slow compared to Read() 4µs,
// but surprisingly if GetQueueStatus() is *not* called, Read()
// becomes largely slower (800µs).
//
// TODO(maruel): This asks for more perf testing before settling on the best
// solution.
// TODO(maruel): Investigate FT_GetStatus().
p, e := h.h.GetQueueStatus()
if p == 0 || e != 0 {
return int(p), toErr("Read/GetQueueStatus", e)
}
v := int(p)
if v > len(b) {
v = len(b)
}
n, e := h.h.Read(b[:v])
return n, toErr("Read", e)
}
// ReadAll blocks to return all the data.
//
// Similar to ioutil.ReadAll() except that it will stop if the context is
// canceled.
func (h *handle) ReadAll(ctx context.Context, b []byte) (int, error) {
// TODO(maruel): Use FT_SetEventNotification() instead of looping when
// waiting for bytes.
for offset := 0; offset != len(b); {
if ctx.Err() != nil {
return offset, io.EOF
}
chunk := len(b) - offset
if chunk > 4096 {
chunk = 4096
}
n, err := h.Read(b[offset : offset+chunk])
if offset += n; err != nil {
return offset, err
}
}
return len(b), nil
}
// WriteFast writes to the USB device.
//
// In practice this takes at least 0.1ms, which limits the effective rate.
//
// There's no guarantee that the data is all written, so it is important to
// check the return value.
func (h *handle) WriteFast(b []byte) (int, error) {
n, e := h.h.Write(b)
return n, toErr("Write", e)
}
// Write blocks until all data is written.
func (h *handle) Write(b []byte) (int, error) {
for offset := 0; offset != len(b); {
chunk := len(b) - offset
if chunk > 4096 {
chunk = 4096
}
p, err := h.WriteFast(b[offset : offset+chunk])
if err != nil {
return offset + p, err
}
if p != 0 {
offset += p
}
}
return len(b), nil
}
// ReadEEPROM reads the EEPROM.
func (h *handle) ReadEEPROM(ee *EEPROM) error {
// The raw data size must be exactly what the device contains.
eepromSize := h.t.EEPROMSize()
if len(ee.Raw) < eepromSize {
ee.Raw = make([]byte, eepromSize)
} else if len(ee.Raw) > eepromSize {
ee.Raw = ee.Raw[:eepromSize]
}
ee2 := d2xx.EEPROM{Raw: ee.Raw}
e := h.h.EEPROMRead(uint32(h.t), &ee2)
ee.Manufacturer = ee2.Manufacturer
ee.ManufacturerID = ee2.ManufacturerID
ee.Desc = ee2.Desc
ee.Serial = ee2.Serial
if e != 0 {
// 15 == FT_EEPROM_NOT_PROGRAMMED
if e != 15 {
return toErr("EEPROMRead", e)
}
// It's a fresh new device. Devices bought via Adafruit already have
// their EEPROM programmed with Adafruit branding but fake devices sold by
// CJMCU are not. Since GetDeviceInfo() above succeeded, we know the
// device type via the USB descriptor, which is sufficient to load the
// driver, which permits to program the EEPROM to "bootstrap" it.
//
// Fill it with an empty yet valid EEPROM content. We don't want to set
// VenID or DevID to 0! Nobody would do that, right?
ee.Raw = make([]byte, h.t.EEPROMSize())
hdr := ee.AsHeader()
hdr.DeviceType = h.t
hdr.VendorID = h.venID
hdr.ProductID = h.devID
}
return nil
}
// WriteEEPROM programs the EEPROM.
func (h *handle) WriteEEPROM(ee *EEPROM) error {
if err := ee.Validate(); err != nil {
return err
}
if len(ee.Raw) != 0 {
hdr := ee.AsHeader()
if hdr == nil {
return errors.New("ftdi: unexpected EEPROM header size")
}
if hdr.DeviceType != h.t {
return errors.New("ftdi: unexpected device type set while programming EEPROM")
}
if hdr.VendorID != h.venID {
return errors.New("ftdi: unexpected VenID set while programming EEPROM")
}
if hdr.ProductID != h.devID {
return errors.New("ftdi: unexpected DevID set while programming EEPROM")
}
}
ee2 := d2xx.EEPROM{
Raw: ee.Raw,
Manufacturer: ee.Manufacturer,
ManufacturerID: ee.ManufacturerID,
Desc: ee.Desc,
Serial: ee.Serial,
}
return toErr("EEPROMWrite", h.h.EEPROMProgram(&ee2))
}
// EraseEEPROM erases all the EEPROM.
//
// Will fail on FT232R and FT245R.
func (h *handle) EraseEEPROM() error {
return toErr("EraseEE", h.h.EraseEE())
}
// ReadUA reads the EEPROM user area.
//
// May return nil when there's nothing programmed yet.
func (h *handle) ReadUA() ([]byte, error) {
size, e := h.h.EEUASize()
if e != 0 {
return nil, toErr("EEUASize", e)
}
if size == 0 {
// Happens on uninitialized EEPROM.
return nil, nil
}
b := make([]byte, size)
if e := h.h.EEUARead(b); e != 0 {
return nil, toErr("EEUARead", e)
}
return b, nil
}
// WriteUA writes to the EEPROM user area.
func (h *handle) WriteUA(ua []byte) error {
size, e := h.h.EEUASize()
if e != 0 {
return toErr("EEUASize", e)
}
if size == 0 {
return errors.New("ftdi: please program EEPROM first")
}
if size < len(ua) {
return fmt.Errorf("ftdi: maximum user area size is %d bytes", size)
}
if size != len(ua) {
b := make([]byte, size)
copy(b, ua)
ua = b
}
if e := h.h.EEUAWrite(ua); e != 0 {
return toErr("EEUAWrite", e)
}
return nil
}
// SetBaudRate sets the baud rate.
func (h *handle) SetBaudRate(f physic.Frequency) error {
if f >= physic.GigaHertz {
return errors.New("ftdi: baud rate too high")
}
v := uint32(f / physic.Hertz)
return toErr("SetBaudRate", h.h.SetBaudRate(v))
}
//
func toErr(s string, e d2xx.Err) error {
if e == 0 {
return nil
}
return errors.New("ftdi: " + s + ": " + e.String())
}

295
vendor/periph.io/x/host/v3/ftdi/i2c.go generated vendored Normal file
View File

@ -0,0 +1,295 @@
// 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.
// This functionality requires MPSSE.
//
// Interfacing I²C:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_113_FTDI_Hi_Speed_USB_To_I2C_Example.pdf
//
// Implementation based on
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_255_USB%20to%20I2C%20Example%20using%20the%20FT232H%20and%20FT201X%20devices.pdf
//
// Page 18: MPSSE does not automatically support clock stretching for I²C.
package ftdi
import (
"context"
"errors"
"fmt"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/physic"
)
const i2cSCL = 1 // D0
const i2cSDAOut = 2 // D1
const i2cSDAIn = 4 // D2
type i2cBus struct {
f *FT232H
pullUp bool
}
// Close stops I²C mode, returns to high speed mode, disable tri-state.
func (d *i2cBus) Close() error {
d.f.mu.Lock()
err := d.stopI2C()
d.f.mu.Unlock()
return err
}
// Duplex implements conn.Conn.
func (d *i2cBus) Duplex() conn.Duplex {
return conn.Half
}
func (d *i2cBus) String() string {
return d.f.String()
}
// SetSpeed implements i2c.Bus.
func (d *i2cBus) SetSpeed(f physic.Frequency) error {
if f > 10*physic.MegaHertz {
return fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 10MHz", f)
}
if f < 100*physic.Hertz {
return fmt.Errorf("d2xx: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.KiloHertz?", f)
}
d.f.mu.Lock()
defer d.f.mu.Unlock()
_, err := d.f.h.MPSSEClock(f * 2 / 3)
return err
}
// Tx implements i2c.Bus.
func (d *i2cBus) Tx(addr uint16, w, r []byte) error {
d.f.mu.Lock()
defer d.f.mu.Unlock()
if err := d.setI2CStart(); err != nil {
return err
}
a := [1]byte{byte(addr)}
if err := d.writeBytes(a[:]); err != nil {
return err
}
if len(w) != 0 {
if err := d.writeBytes(w); err != nil {
return err
}
}
if len(r) != 0 {
if err := d.readBytes(r); err != nil {
return err
}
}
if err := d.setI2CStop(); err != nil {
return err
}
return d.setI2CLinesIdle()
}
// SCL implements i2c.Pins.
func (d *i2cBus) SCL() gpio.PinIO {
return d.f.D0
}
// SDA implements i2c.Pins.
func (d *i2cBus) SDA() gpio.PinIO {
return d.f.D1
}
// setupI2C initializes the MPSSE to the state to run an I²C transaction.
//
// Defaults to 400kHz.
//
// When pullUp is true; output alternates between Out(Low) and In(PullUp).
//
// when pullUp is false; pins are set in Tristate so Out(High) becomes float
// instead of drive High. Low still drives low. That's called open collector.
func (d *i2cBus) setupI2C(pullUp bool) error {
if pullUp {
return errors.New("d2xx: PullUp will soon be implemented")
}
// TODO(maruel): We could set these only *during* the I²C operation, which
// would make more sense.
f := 400 * physic.KiloHertz
clk := ((30 * physic.MegaHertz / f) - 1) * 2 / 3
buf := [4 + 3]byte{
clock3Phase,
clock30MHz, byte(clk), byte(clk >> 8),
}
cmd := buf[:4]
if !d.pullUp {
// TODO(maruel): Do not mess with other GPIOs tristate.
cmd = append(cmd, dataTristate, 7, 0)
}
if _, err := d.f.h.Write(cmd); err != nil {
return err
}
d.f.usingI2C = true
d.pullUp = pullUp
return d.setI2CLinesIdle()
}
// stopI2C resets the MPSSE to a more "normal" state.
func (d *i2cBus) stopI2C() error {
// Resets to 30MHz.
buf := [4 + 3]byte{
clock2Phase,
clock30MHz, 0, 0,
}
cmd := buf[:4]
if !d.pullUp {
// TODO(maruel): Do not mess with other GPIOs tristate.
cmd = append(cmd, dataTristate, 0, 0)
}
_, err := d.f.h.Write(cmd)
d.f.usingI2C = false
return err
}
// setI2CLinesIdle sets all D0 and D1 lines high.
//
// Does not touch D3~D7.
func (d *i2cBus) setI2CLinesIdle() error {
const mask = 0xFF &^ (i2cSCL | i2cSDAOut | i2cSDAIn)
// TODO(maruel): d.pullUp
d.f.dbus.direction = d.f.dbus.direction&mask | i2cSCL | i2cSDAOut
d.f.dbus.value = d.f.dbus.value & mask
cmd := [...]byte{gpioSetD, d.f.dbus.value | i2cSCL | i2cSDAOut, d.f.dbus.direction}
_, err := d.f.h.Write(cmd[:])
return err
}
// setI2CStart starts an I²C transaction.
//
// Does not touch D3~D7.
func (d *i2cBus) setI2CStart() error {
// TODO(maruel): d.pullUp
dir := d.f.dbus.direction
v := d.f.dbus.value
// Assumes last setup was d.setI2CLinesIdle(), e.g. D0 and D1 are high, so
// skip this.
//
// Runs the command 4 times as a way to delay execution.
cmd := [...]byte{
// SCL high, SDA low for 600ns
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
// SCL low, SDA low
gpioSetD, v, dir,
gpioSetD, v, dir,
gpioSetD, v, dir,
}
_, err := d.f.h.Write(cmd[:])
return err
}
// setI2CStop completes an I²C transaction.
//
// Does not touch D3~D7.
func (d *i2cBus) setI2CStop() error {
// TODO(maruel): d.pullUp
dir := d.f.dbus.direction
v := d.f.dbus.value
// Runs the command 4 times as a way to delay execution.
cmd := [...]byte{
// SCL low, SDA low
gpioSetD, v, dir,
gpioSetD, v, dir,
gpioSetD, v, dir,
gpioSetD, v, dir,
// SCL high, SDA low
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
// SCL high, SDA high
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
}
_, err := d.f.h.Write(cmd[:])
return err
}
// writeBytes writes multiple bytes within an I²C transaction.
//
// Does not touch D3~D7.
func (d *i2cBus) writeBytes(w []byte) error {
// TODO(maruel): d.pullUp
dir := d.f.dbus.direction
v := d.f.dbus.value
// TODO(maruel): WAT?
if err := d.f.h.Flush(); err != nil {
return err
}
// TODO(maruel): Implement both with and without NAK check.
var r [1]byte
cmd := [...]byte{
// Data out, the 0 will be replaced with the byte.
dataOut | dataOutFall, 0, 0, 0,
// Set back to idle.
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
// Read ACK/NAK.
dataIn | dataBit, 0,
flush,
}
for _, c := range w {
cmd[3] = c
if _, err := d.f.h.Write(cmd[:]); err != nil {
return err
}
if _, err := d.f.h.ReadAll(context.Background(), r[:]); err != nil {
return err
}
if r[0]&1 == 0 {
return errors.New("got NAK")
}
}
return nil
}
// readBytes reads multiple bytes within an I²C transaction.
//
// Does not touch D3~D7.
func (d *i2cBus) readBytes(r []byte) error {
// TODO(maruel): d.pullUp
dir := d.f.dbus.direction
v := d.f.dbus.value
cmd := [...]byte{
// Read 8 bits.
dataIn | dataBit, 7,
// Send ACK/NAK.
dataOut | dataOutFall | dataBit, 0, 0,
// Set back to idle.
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
// Force read buffer flush. This is only necessary if NAK are not ignored.
flush,
}
for i := range r {
if i == len(r)-1 {
// NAK.
cmd[4] = 0x80
}
if _, err := d.f.h.Write(cmd[:]); err != nil {
return err
}
if _, err := d.f.h.ReadAll(context.Background(), r[i:1]); err != nil {
return err
}
}
return nil
}
var _ i2c.BusCloser = &i2cBus{}
var _ i2c.Pins = &i2cBus{}

452
vendor/periph.io/x/host/v3/ftdi/mpsse.go generated vendored Normal file
View File

@ -0,0 +1,452 @@
// 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.
// MPSSE is Multi-Protocol Synchronous Serial Engine
//
// MPSSE basics:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_135_MPSSE_Basics.pdf
//
// MPSSE and MCU emulation modes:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
package ftdi
import (
"context"
"errors"
"fmt"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
const (
// TDI/TDO serial operation synchronised on clock edges.
//
// Long streams (default):
// - [1, 65536] bytes (length is sent minus one, requires 8 bits multiple)
// <op>, <LengthLow-1>, <LengthHigh-1>, <byte0>, ..., <byteN>
//
// Short streams (dataBit is specified):
// - [1, 8] bits
// <op>, <Length-1>, <byte>
//
// When both dataOut and dataIn are specified, one of dataOutFall or
// dataInFall should be specified, at least for most sane protocols.
//
// Flags:
dataOut byte = 0x10 // Enable output, default on +VE (Rise)
dataIn byte = 0x20 // Enable input, default on +VE (Rise)
dataOutFall byte = 0x01 // instead of Rise
dataInFall byte = 0x04 // instead of Rise
dataLSBF byte = 0x08 // instead of MSBF
dataBit byte = 0x02 // instead of Byte
// Data line drives low when the data is 0 and tristates on data 1. This is
// used with I²C.
// <op>, <ADBus pins>, <ACBus pins>
dataTristate byte = 0x9E
// TSM operation (for JTAG).
//
// - Send bits 6 to 0 to the TMS pin using LSB or MSB.
// - Bit 7 is passed to TDI/DO before the first clock of TMS and is held
// static for the duration of TMS clocking.
//
// <op>, <Length>, <byte>
tmsOutLSBFRise byte = 0x4A
tmsOutLSBFFall byte = 0x4B
tmsIOLSBInRise byte = 0x6A
tmsIOLSBInFall byte = 0x6B
// Unclear: 0x6E and 0x6F
// GPIO operation.
//
// - Operates on 8 GPIOs at a time, e.g. C0~C7 or D0~D7.
// - Direction 1 means output, 0 means input.
//
// <op>, <value>, <direction>
gpioSetD byte = 0x80
gpioSetC byte = 0x82
// <op>, returns <value>
gpioReadD byte = 0x81
gpioReadC byte = 0x83
// Internal loopback.
//
// Connects TDI and TDO together.
internalLoopbackEnable byte = 0x84
internalLoopbackDisable byte = 0x85
// Clock.
//
// The TCK/SK has a 50% duty cycle.
//
// The inactive clock state can be set via the gpioSetD command and control
// bit 0.
//
// By default, the base clock is 6MHz via a 5x divisor. On
// FT232H/FT2232H/FT4232H, the 5x divisor can be disabled.
clock30MHz byte = 0x8A
clock6MHz byte = 0x8B
// Sets clock divisor.
//
// The effective value depends if clock30MHz was sent or not.
//
// - 0(1) 6MHz / 30MHz
// - 1(2) 3MHz / 15MHz
// - 2(3) 2MHz / 10MHz
// - 3(4) 1.5MHz / 7.5MHz
// - 4(5) 1.25MHz / 6MHz
// - ...
// - 0xFFFF(65536) 91.553Hz / 457.763Hz
//
// <op>, <valueL-1>, <valueH-1>
clockSetDivisor byte = 0x86
// Uses 3 phases data clocking: data is valid on both clock edges. Needed
// for I²C.
clock3Phase byte = 0x8C
// Uses normal 2 phases data clocking.
clock2Phase byte = 0x8D
// Enables clock even while not doing any operation. Used with JTAG.
// Enables the clock between [1, 8] pulses.
// <op>, <length-1>
clockOnShort byte = 0x8E
// Enables the clock between [8, 524288] pulses in 8 multiples.
// <op>, <lengthL-1>, <lengthH-1>
clockOnLong byte = 0x8F
// Enables clock until D5 is high or low. Used with JTAG.
clockUntilHigh byte = 0x94
clockUntilLow byte = 0x95
// <op>, <lengthL-1>, <lengthH-1> in 8 multiples.
clockUntilHighLong byte = 0x9C
clockUntilLowLong byte = 0x9D
// Enables adaptive clocking. Used with JTAG.
//
// This causes the controller to wait for D7 signal state as an ACK.
clockAdaptive byte = 0x96
// Disables adaptive clocking.
clockNormal byte = 0x97
// CPU mode.
//
// Access the device registers like a memory mapped device.
//
// <op>, <addrLow>
cpuReadShort byte = 0x90
// <op>, <addrHi>, <addrLow>
cpuReadFar byte = 0x91
// <op>, <addrLow>, <data>
cpuWriteShort byte = 0x92
// <op>, <addrHi>, <addrLow>, <data>
cpuWriteFar byte = 0x91
// Buffer operations.
//
// Flush the buffer back to the host.
flush byte = 0x87
// Wait until D5 (JTAG) or I/O1 (CPU) is high. Once it is detected as
// high, the MPSSE engine moves on to process the next instruction.
waitHigh byte = 0x88
waitLow byte = 0x89
)
// InitMPSSE sets the device into MPSSE mode.
//
// This requires a f232h, ft2232, ft2232h or a ft4232h.
//
// Use only one of Init or InitMPSSE.
func (h *handle) InitMPSSE() error {
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_255_USB%20to%20I2C%20Example%20using%20the%20FT232H%20and%20FT201X%20devices.pdf
// Pre-state:
// - Write EEPROM i.IsFifo = true so the device DBus is started in tristate.
// Try to verify the MPSSE controller without initializing it first. This is
// the 'happy path', which enables reusing the device is its current state
// without affecting current GPIO state.
if h.mpsseVerify() != nil {
// Do a full reset. Just trying to set the MPSSE controller will
// likely not work. That's a layering violation (since the retry with reset
// is done in driver.go) but we've survived worse things...
//
// TODO(maruel): This is not helping in practice, this need to be fine
// tuned.
if err := h.Reset(); err != nil {
return err
}
if err := h.Init(); err != nil {
return err
}
if err := h.SetBitMode(0, bitModeMpsse); err != nil {
return err
}
if err := h.mpsseVerify(); err != nil {
return err
}
}
// Initialize MPSSE to a known state.
// Reset the clock since it is impossible to read back the current clock rate.
// Reset all the GPIOs are inputs since it is impossible to read back the
// state of each GPIO (if they are input or output).
cmd := []byte{
clock30MHz, clockNormal, clock2Phase, internalLoopbackDisable,
gpioSetC, 0x00, 0x00,
gpioSetD, 0x00, 0x00,
}
if _, err := h.Write(cmd); err != nil {
return err
}
// Success!!
return nil
}
// mpsseVerify sends an invalid MPSSE command and verifies the returned value
// is incorrect.
//
// In practice this takes around 2ms.
func (h *handle) mpsseVerify() error {
var b [16]byte
for _, v := range []byte{0xAA, 0xAB} {
// Write a bad command and ensure it returned correctly.
// Unlike what the application note proposes, include a flush op right
// after. Without the flush, the device will only flush after the delay
// specified to SetLatencyTimer. The flush removes this unneeded wait,
// which enables increasing the delay specified to SetLatencyTimer.
b[0] = v
b[1] = flush
if _, err := h.Write(b[:2]); err != nil {
return fmt.Errorf("d2xx: mpsseVerify: %v", err)
}
// Sometimes, especially right after a reset, the device spews a few bytes.
// Discard them. This significantly increases the odds of a successful
// initialization.
p, e := h.h.GetQueueStatus()
if e != 0 {
return toErr("Read/GetQueueStatus", e)
}
for p > 2 {
l := int(p) - 2
if l > len(b) {
l = len(b)
}
// Discard the overflow bytes.
ctx, cancel := context200ms()
defer cancel()
if _, err := h.ReadAll(ctx, b[:l]); err != nil {
return fmt.Errorf("d2xx: mpsseVerify: %v", err)
}
p -= uint32(l)
}
// Custom implementation, as we want to flush any stray byte.
ctx, cancel := context200ms()
defer cancel()
if _, err := h.ReadAll(ctx, b[:2]); err != nil {
return fmt.Errorf("d2xx: mpsseVerify: %v", err)
}
// 0xFA means invalid command, 0xAA is the command echoed back.
if b[0] != 0xFA || b[1] != v {
return fmt.Errorf("d2xx: mpsseVerify: failed test for byte %#x: %#x", v, b)
}
}
return nil
}
//
// MPSSERegRead reads the memory mapped registers from the device.
func (h *handle) MPSSERegRead(addr uint16) (byte, error) {
// Unlike most other operations, the uint16 byte order is <hi>, <lo>.
b := [...]byte{cpuReadFar, byte(addr >> 8), byte(addr), flush}
if _, err := h.Write(b[:]); err != nil {
return 0, err
}
ctx, cancel := context200ms()
defer cancel()
_, err := h.ReadAll(ctx, b[:1])
return b[0], err
}
// MPSSEClock sets the clock at the closest value and returns it.
func (h *handle) MPSSEClock(f physic.Frequency) (physic.Frequency, error) {
// TODO(maruel): Memory clock and skip if the same value.
clk := clock30MHz
base := 30 * physic.MegaHertz
div := base / f
if div >= 65536 {
clk = clock6MHz
base /= 5
div = base / f
if div >= 65536 {
return 0, errors.New("d2xx: clock frequency is too low")
}
}
b := [...]byte{clk, clockSetDivisor, byte(div - 1), byte((div - 1) >> 8)}
_, err := h.Write(b[:])
return base / div, err
}
// mpsseTxOp returns the right MPSSE command byte for the stream.
func mpsseTxOp(w, r bool, ew, er gpio.Edge, lsbf bool) byte {
op := byte(0)
if lsbf {
op |= dataLSBF
}
if w {
op |= dataOut
if ew == gpio.FallingEdge {
op |= dataOutFall
}
}
if r {
op |= dataIn
if er == gpio.FallingEdge {
op |= dataInFall
}
}
return op
}
// MPSSETx runs a transaction on the clock on pins D0, D1 and D2.
//
// It can only do it on a multiple of 8 bits.
func (h *handle) MPSSETx(w, r []byte, ew, er gpio.Edge, lsbf bool) error {
l := len(w)
if len(w) != 0 {
// TODO(maruel): This is easy to fix by daisy chaining operations.
if len(w) > 65536 {
return errors.New("d2xx: write buffer too long; max 65536")
}
}
if len(r) != 0 {
if len(r) > 65536 {
return errors.New("d2xx: read buffer too long; max 65536")
}
if l != 0 && len(r) != l {
return errors.New("d2xx: mismatched buffer lengths")
}
l = len(r)
}
// The FT232H has 1Kb Tx and Rx buffers. So partial writes should be done.
// TODO(maruel): Test.
// Flush can be useful if rbits != 0.
op := mpsseTxOp(len(w) != 0, len(r) != 0, ew, er, lsbf)
cmd := []byte{op, byte(l - 1), byte((l - 1) >> 8)}
cmd = append(cmd, w...)
if len(r) != 0 {
cmd = append(cmd, flush)
}
if _, err := h.Write(cmd); err != nil {
return err
}
if len(r) != 0 {
ctx, cancel := context200ms()
defer cancel()
_, err := h.ReadAll(ctx, r)
return err
}
return nil
}
// MPSSETxShort runs a transaction on the clock pins D0, D1 and D2 for a byte
// or less: between 1 and 8 bits.
func (h *handle) MPSSETxShort(w byte, wbits, rbits int, ew, er gpio.Edge, lsbf bool) (byte, error) {
op := byte(dataBit)
if lsbf {
op |= dataLSBF
}
l := wbits
if wbits != 0 {
if wbits > 8 {
return 0, errors.New("d2xx: write buffer too long; max 8")
}
op |= dataOut
if ew == gpio.FallingEdge {
op |= dataOutFall
}
}
if rbits != 0 {
if rbits > 8 {
return 0, errors.New("d2xx: read buffer too long; max 8")
}
op |= dataIn
if er == gpio.FallingEdge {
op |= dataInFall
}
if l != 0 && rbits != l {
return 0, errors.New("d2xx: mismatched buffer lengths")
}
l = rbits
}
b := [3]byte{op, byte(l - 1)}
cmd := b[:2]
if wbits != 0 {
cmd = append(cmd, w)
}
if rbits != 0 {
cmd = append(cmd, flush)
}
if _, err := h.Write(cmd); err != nil {
return 0, err
}
if rbits != 0 {
ctx, cancel := context200ms()
defer cancel()
_, err := h.ReadAll(ctx, b[:1])
return b[0], err
}
return 0, nil
}
// MPSSECBus operates on 8 GPIOs at a time C0~C7.
//
// Direction 1 means output, 0 means input.
func (h *handle) MPSSECBus(mask, value byte) error {
b := [...]byte{gpioSetC, value, mask}
_, err := h.Write(b[:])
return err
}
// MPSSEDBus operates on 8 GPIOs at a time D0~D7.
//
// Direction 1 means output, 0 means input.
func (h *handle) MPSSEDBus(mask, value byte) error {
b := [...]byte{gpioSetD, value, mask}
_, err := h.Write(b[:])
return err
}
// MPSSECBusRead reads all the CBus pins C0~C7.
func (h *handle) MPSSECBusRead() (byte, error) {
b := [...]byte{gpioReadC, flush}
if _, err := h.Write(b[:]); err != nil {
return 0, err
}
ctx, cancel := context200ms()
defer cancel()
if _, err := h.ReadAll(ctx, b[:1]); err != nil {
return 0, err
}
return b[0], nil
}
// MPSSEDBusRead reads all the DBus pins D0~D7.
func (h *handle) MPSSEDBusRead() (byte, error) {
b := [...]byte{gpioReadD, flush}
if _, err := h.Write(b[:]); err != nil {
return 0, err
}
ctx, cancel := context200ms()
defer cancel()
if _, err := h.ReadAll(ctx, b[:1]); err != nil {
return 0, err
}
return b[0], nil
}
func context200ms() (context.Context, func()) {
return context.WithTimeout(context.Background(), 200*time.Millisecond)
}

205
vendor/periph.io/x/host/v3/ftdi/mpsse_gpio.go generated vendored Normal file
View File

@ -0,0 +1,205 @@
// 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 ftdi
import (
"errors"
"fmt"
"strconv"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
// gpiosMPSSE is a slice of 8 GPIO pins driven via MPSSE.
//
// This permits keeping a cache.
type gpiosMPSSE struct {
// Immutable.
h *handle
cbus bool // false if D bus
pins [8]gpioMPSSE
// Cache of values
direction byte
value byte
}
func (g *gpiosMPSSE) init(name string) {
s := "D"
if g.cbus {
s = "C"
}
// Configure pulls; pull ups are 75kΩ.
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_184%20FTDI%20Device%20Input%20Output%20Pin%20States.pdf
// has a good table.
// D0, D2 and D4 go in high impedance before going into pull up.
// TODO(maruel): The pull on CBus depends on EEPROM!
for i := range g.pins {
g.pins[i].a = g
g.pins[i].n = name + "." + s + strconv.Itoa(i)
g.pins[i].num = i
g.pins[i].dp = gpio.PullUp
}
if g.cbus {
// That's just the default EEPROM value.
g.pins[7].dp = gpio.PullDown
}
}
func (g *gpiosMPSSE) in(n int) error {
if g.h == nil {
return errors.New("d2xx: device not open")
}
g.direction = g.direction & ^(1 << uint(n))
if g.cbus {
return g.h.MPSSECBus(g.direction, g.value)
}
return g.h.MPSSEDBus(g.direction, g.value)
}
func (g *gpiosMPSSE) read() (byte, error) {
if g.h == nil {
return 0, errors.New("d2xx: device not open")
}
var err error
if g.cbus {
g.value, err = g.h.MPSSECBusRead()
} else {
g.value, err = g.h.MPSSEDBusRead()
}
return g.value, err
}
func (g *gpiosMPSSE) out(n int, l gpio.Level) error {
if g.h == nil {
return errors.New("d2xx: device not open")
}
g.direction = g.direction | (1 << uint(n))
if l {
g.value |= 1 << uint(n)
} else {
g.value &^= 1 << uint(n)
}
if g.cbus {
return g.h.MPSSECBus(g.direction, g.value)
}
return g.h.MPSSEDBus(g.direction, g.value)
}
//
// gpioMPSSE is a GPIO pin on a FTDI device driven via MPSSE.
//
// gpioMPSSE implements gpio.PinIO.
//
// It is immutable and stateless.
type gpioMPSSE struct {
a *gpiosMPSSE
n string
num int
dp gpio.Pull
}
// String implements pin.Pin.
func (g *gpioMPSSE) String() string {
return g.n
}
// Name implements pin.Pin.
func (g *gpioMPSSE) Name() string {
return g.n
}
// Number implements pin.Pin.
func (g *gpioMPSSE) Number() int {
return g.num
}
// Function implements pin.Pin.
func (g *gpioMPSSE) Function() string {
s := "Out/"
m := byte(1 << uint(g.num))
if g.a.direction&m == 0 {
s = "In/"
_, _ = g.a.read()
}
return s + gpio.Level(g.a.value&m != 0).String()
}
// Halt implements gpio.PinIO.
func (g *gpioMPSSE) Halt() error {
return nil
}
// In implements gpio.PinIn.
func (g *gpioMPSSE) In(pull gpio.Pull, e gpio.Edge) error {
if e != gpio.NoEdge {
// We could support it on D5.
return errors.New("d2xx: edge triggering is not supported")
}
if pull != g.dp && pull != gpio.PullNoChange {
// TODO(maruel): This needs to be redone:
// - EEPROM values FT232hCBusTristatePullUp and FT232hCBusPwrEnable can be
// used to control individual CBus pins.
// - dataTristate enables gpio.Float when set to output High, but I don't
// know if it will enable reading the value (?). This needs to be
// confirmed.
return fmt.Errorf("d2xx: pull %s is not supported; try %s", pull, g.dp)
}
return g.a.in(g.num)
}
// Read implements gpio.PinIn.
func (g *gpioMPSSE) Read() gpio.Level {
v, _ := g.a.read()
return gpio.Level(v&(1<<uint(g.num)) != 0)
}
// WaitForEdge implements gpio.PinIn.
func (g *gpioMPSSE) WaitForEdge(t time.Duration) bool {
return false
}
// DefaultPull implements gpio.PinIn.
func (g *gpioMPSSE) DefaultPull() gpio.Pull {
return g.dp
}
// Pull implements gpio.PinIn. The resistor is 75kΩ.
func (g *gpioMPSSE) Pull() gpio.Pull {
// See In() for the challenges.
return g.dp
}
// Out implements gpio.PinOut.
func (g *gpioMPSSE) Out(l gpio.Level) error {
return g.a.out(g.num, l)
}
// PWM implements gpio.PinOut.
func (g *gpioMPSSE) PWM(d gpio.Duty, f physic.Frequency) error {
return errors.New("d2xx: not implemented")
}
/*
func (g *gpioMPSSE) Drive() physic.ElectricCurrent {
//return g.a.ee.CDriveCurrent * physic.MilliAmpere
return 2 * physic.MilliAmpere
}
func (g *gpioMPSSE) SlewLimit() bool {
//return g.a.ee.CSlowSlew
return false
}
func (g *gpioMPSSE) Hysteresis() bool {
//return g.a.ee.DSchmittInput
return true
}
*/
var _ gpio.PinIO = &gpioMPSSE{}

85
vendor/periph.io/x/host/v3/ftdi/pin.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
// 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.
// Emulate independent GPIOs.
package ftdi
import (
"errors"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
// invalidPin is a non-working (not implemented) pin on a FTDI device.
//
// invalidPin implements gpio.PinIO.
type invalidPin struct {
n string
num int
}
// String implements pin.Pin.
func (p *invalidPin) String() string {
return p.n
}
// Name implements pin.Pin.
func (p *invalidPin) Name() string {
return p.n
}
// Number implements pin.Pin.
func (p *invalidPin) Number() int {
return p.num
}
// Function implements pin.Pin.
func (p *invalidPin) Function() string {
return "N/A"
}
// Halt implements gpio.PinIO.
func (p *invalidPin) Halt() error {
return nil
}
// In implements gpio.PinIn.
func (p *invalidPin) In(pull gpio.Pull, e gpio.Edge) error {
return errors.New("d2xx: to be implemented")
}
// Read implements gpio.PinIn.
func (p *invalidPin) Read() gpio.Level {
return gpio.Low
}
// WaitForEdge implements gpio.PinIn.
func (p *invalidPin) WaitForEdge(t time.Duration) bool {
return false
}
// Pull implements gpio.PinIn.
func (p *invalidPin) Pull() gpio.Pull {
return gpio.PullNoChange
}
// DefaultPull implements gpio.PinIn.
func (p *invalidPin) DefaultPull() gpio.Pull {
return gpio.PullNoChange
}
// Out implements gpio.PinOut.
func (p *invalidPin) Out(l gpio.Level) error {
return errors.New("d2xx: to be implemented")
}
// PWM implements gpio.PinOut.
func (p *invalidPin) PWM(d gpio.Duty, f physic.Frequency) error {
return errors.New("d2xx: to be implemented")
}
var _ gpio.PinIO = &invalidPin{}

697
vendor/periph.io/x/host/v3/ftdi/spi.go generated vendored Normal file
View File

@ -0,0 +1,697 @@
// 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.
// This functionality requires MPSSE.
//
// Interfacing SPI:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_114_FTDI_Hi_Speed_USB_To_SPI_Example.pdf
//
// Implementation based on
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_180_FT232H%20MPSSE%20Example%20-%20USB%20Current%20Meter%20using%20the%20SPI%20interface.pdf
package ftdi
import (
"context"
"errors"
"fmt"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/spi"
)
// spiMPSEEPort is an SPI port over a FTDI device in MPSSE mode using the data
// command on the AD bus.
type spiMPSEEPort struct {
c spiMPSEEConn
// Mutable.
maxFreq physic.Frequency
}
func (s *spiMPSEEPort) Close() error {
s.c.f.mu.Lock()
s.c.f.usingSPI = false
s.maxFreq = 0
s.c.edgeInvert = false
s.c.clkActiveLow = false
s.c.noCS = false
s.c.lsbFirst = false
s.c.halfDuplex = false
s.c.f.mu.Unlock()
return nil
}
func (s *spiMPSEEPort) String() string {
return s.c.f.String()
}
// Connect implements spi.Port.
func (s *spiMPSEEPort) Connect(f physic.Frequency, m spi.Mode, bits int) (spi.Conn, error) {
if f > physic.GigaHertz {
return nil, fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 30MHz", f)
}
if f > 30*physic.MegaHertz {
// TODO(maruel): Figure out a way to communicate that the speed was lowered.
// https://github.com/google/periph/issues/255
f = 30 * physic.MegaHertz
}
if f < 100*physic.Hertz {
return nil, fmt.Errorf("d2xx: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?", f)
}
if bits&7 != 0 {
return nil, errors.New("d2xx: bits must be multiple of 8")
}
if bits != 8 {
return nil, errors.New("d2xx: implement bits per word above 8")
}
s.c.f.mu.Lock()
defer s.c.f.mu.Unlock()
s.c.noCS = m&spi.NoCS != 0
s.c.halfDuplex = m&spi.HalfDuplex != 0
s.c.lsbFirst = m&spi.LSBFirst != 0
m &^= spi.NoCS | spi.HalfDuplex | spi.LSBFirst
if s.c.halfDuplex {
return nil, errors.New("d2xx: spi.HalfDuplex is not yet supported (implementing wouldn't be too hard, please submit a PR")
}
if m < 0 || m > 3 {
return nil, errors.New("d2xx: unknown spi mode")
}
s.c.edgeInvert = m&1 != 0
s.c.clkActiveLow = m&2 != 0
if s.maxFreq == 0 || f < s.maxFreq {
// TODO(maruel): We could set these only *during* the SPI operation, which
// would make more sense.
if _, err := s.c.f.h.MPSSEClock(f); err != nil {
return nil, err
}
s.maxFreq = f
}
s.c.resetIdle()
if err := s.c.f.h.MPSSEDBus(s.c.f.dbus.direction, s.c.f.dbus.value); err != nil {
return nil, err
}
s.c.f.usingSPI = true
return &s.c, nil
}
// LimitSpeed implements spi.Port.
func (s *spiMPSEEPort) LimitSpeed(f physic.Frequency) error {
if f > physic.GigaHertz {
return fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 30MHz", f)
}
if f > 30*physic.MegaHertz {
f = 30 * physic.MegaHertz
}
if f < 100*physic.Hertz {
return errors.New("d2xx: minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?")
}
s.c.f.mu.Lock()
defer s.c.f.mu.Unlock()
if s.maxFreq != 0 && s.maxFreq <= f {
return nil
}
s.maxFreq = f
// TODO(maruel): We could set these only *during* the SPI operation, which
// would make more sense.
_, err := s.c.f.h.MPSSEClock(s.maxFreq)
return err
}
// CLK returns the SCK (clock) pin.
func (s *spiMPSEEPort) CLK() gpio.PinOut {
return s.c.CLK()
}
// MOSI returns the SDO (master out, slave in) pin.
func (s *spiMPSEEPort) MOSI() gpio.PinOut {
return s.c.MOSI()
}
// MISO returns the SDI (master in, slave out) pin.
func (s *spiMPSEEPort) MISO() gpio.PinIn {
return s.c.MISO()
}
// CS returns the CSN (chip select) pin.
func (s *spiMPSEEPort) CS() gpio.PinOut {
return s.c.CS()
}
type spiMPSEEConn struct {
// Immutable.
f *FT232H
// Initialized at Connect().
edgeInvert bool // CPHA=1
clkActiveLow bool // CPOL=1
noCS bool // CS line is not changed
lsbFirst bool // Default is MSB first
halfDuplex bool // 3 wire mode
}
func (s *spiMPSEEConn) String() string {
return s.f.String()
}
func (s *spiMPSEEConn) Tx(w, r []byte) error {
var p = [1]spi.Packet{{W: w, R: r}}
return s.TxPackets(p[:])
}
func (s *spiMPSEEConn) Duplex() conn.Duplex {
// TODO(maruel): Support half if there's a need.
return conn.Full
}
func (s *spiMPSEEConn) TxPackets(pkts []spi.Packet) error {
// Verification.
for _, p := range pkts {
if p.KeepCS {
return errors.New("d2xx: implement spi.Packet.KeepCS")
}
if p.BitsPerWord&7 != 0 {
return errors.New("d2xx: bits must be a multiple of 8")
}
if p.BitsPerWord != 0 && p.BitsPerWord != 8 {
return errors.New("d2xx: implement spi.Packet.BitsPerWord")
}
if err := verifyBuffers(p.W, p.R); err != nil {
return err
}
}
s.f.mu.Lock()
defer s.f.mu.Unlock()
const clk = byte(1) << 0
const mosi = byte(1) << 1
const miso = byte(1) << 2
const cs = byte(1) << 3
s.resetIdle()
idle := s.f.dbus.value
start1 := idle
if !s.noCS {
start1 &^= cs
}
// In mode 0 and 2, start2 is not needed.
start2 := start1
stop := idle
if s.edgeInvert {
// This is needed to 'prime' the clock.
start2 ^= clk
// With mode 1 and 3, keep the clock steady while CS is being deasserted to
// not create a spurious clock.
stop ^= clk
}
ew := gpio.FallingEdge
er := gpio.RisingEdge
if s.edgeInvert {
ew, er = er, ew
}
if s.clkActiveLow {
// TODO(maruel): Not sure.
ew, er = er, ew
}
// FT232H claims 512 USB packet support, so to reduce the chatter over USB,
// try to make all I/O be aligned on this amount. This also removes the need
// for heap usage. The idea is to always trail reads by one buffer. This is
// fine as the device has 1024 byte read buffer. Operations look like this:
// W, W, R, W, R, W, R, R
// This enables reducing the I/O gaps between USB packets as the device is
// always busy with operations.
var buf [512]byte
cmd := buf[:0]
keptCS := false
// Loop, without increasing the index.
for _, p := range pkts {
if len(p.W) == 0 && len(p.R) == 0 {
continue
}
// TODO(maruel): s.halfDuplex.
if !keptCS {
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, idle, s.f.dbus.direction)
}
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, start1, s.f.dbus.direction)
}
}
if s.edgeInvert {
// This is needed to 'prime' the clock.
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, start2, s.f.dbus.direction)
}
}
op := mpsseTxOp(len(p.W) != 0, len(p.R) != 0, ew, er, s.lsbFirst)
// Do an I/O loop. We can mutate p here because it is a copy.
// TODO(maruel): Have the pipeline cross the packet boundary.
if len(p.W) == 0 {
// Have the write buffer point to the read one. This saves from
// allocating memory. The side effect is that it will write whatever
// happened to be in the read buffer.
p.W = p.R[:]
}
pendingRead := 0
for len(p.W) != 0 {
// op, sizelo, sizehi.
chunk := len(buf) - 3 - len(cmd)
if l := len(p.W); chunk > l {
chunk = l
}
cmd = append(cmd, op, byte(chunk-1), byte((chunk-1)>>8))
cmd = append(cmd, p.W[:chunk]...)
p.W = p.W[chunk:]
if _, err := s.f.h.WriteFast(cmd); err != nil {
return err
}
cmd = buf[:0]
// TODO(maruel): Read 62 bytes at a time?
// Delay reading by 512 bytes.
if pendingRead >= 512 {
if len(p.R) != 0 {
// Align reads on 512 bytes exactly, aligned on USB packet size.
if _, err := s.f.h.ReadAll(context.Background(), p.R[:512]); err != nil {
return err
}
p.R = p.R[512:]
pendingRead -= 512
}
}
pendingRead += chunk
}
// Do not forget to read whatever is pending.
// TODO(maruel): Investigate if a flush helps.
if len(p.R) != 0 {
// Send a flush to not wait for data.
cmd = append(cmd, flush)
if _, err := s.f.h.WriteFast(cmd); err != nil {
return err
}
cmd = buf[:0]
if _, err := s.f.h.ReadAll(context.Background(), p.R); err != nil {
return err
}
}
// TODO(maruel): Inject this in the write if it fits (it will generally
// do). That will save one USB I/O, which is not insignificant.
keptCS = p.KeepCS
if !keptCS {
cmd = append(cmd, flush)
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, stop, s.f.dbus.direction)
}
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, idle, s.f.dbus.direction)
}
if _, err := s.f.h.WriteFast(cmd); err != nil {
return err
}
cmd = buf[:0]
}
}
return nil
}
// CLK returns the SCK (clock) pin.
func (s *spiMPSEEConn) CLK() gpio.PinOut {
return s.f.D0
}
// MOSI returns the SDO (master out, slave in) pin.
func (s *spiMPSEEConn) MOSI() gpio.PinOut {
return s.f.D1
}
// MISO returns the SDI (master in, slave out) pin.
func (s *spiMPSEEConn) MISO() gpio.PinIn {
return s.f.D2
}
// CS returns the CSN (chip select) pin.
func (s *spiMPSEEConn) CS() gpio.PinOut {
return s.f.D3
}
// resetIdle sets D0~D3. D0, D1 and D3 are output but only touch D3 is CS is
// used.
func (s *spiMPSEEConn) resetIdle() {
const clk = byte(1) << 0
const mosi = byte(1) << 1
const miso = byte(1) << 2
const cs = byte(1) << 3
if !s.noCS {
s.f.dbus.direction &= 0xF0
s.f.dbus.direction |= cs
s.f.dbus.value &= 0xF0
s.f.dbus.value |= cs
} else {
s.f.dbus.value &= 0xF8
s.f.dbus.direction &= 0xF8
}
s.f.dbus.direction |= mosi | clk
if s.clkActiveLow {
// Clock idles high.
s.f.dbus.value |= clk
}
}
//
// spiSyncPort is an SPI port over a FTDI device in synchronous bit-bang mode.
type spiSyncPort struct {
c spiSyncConn
// Mutable.
maxFreq physic.Frequency
}
func (s *spiSyncPort) Close() error {
s.c.f.mu.Lock()
s.c.f.usingSPI = false
s.maxFreq = 0
s.c.edgeInvert = false
s.c.clkActiveLow = false
s.c.noCS = false
s.c.lsbFirst = false
s.c.halfDuplex = false
s.c.f.mu.Unlock()
return nil
}
func (s *spiSyncPort) String() string {
return s.c.f.String()
}
const ft232rMaxSpeed = 3 * physic.MegaHertz
// Connect implements spi.Port.
func (s *spiSyncPort) Connect(f physic.Frequency, m spi.Mode, bits int) (spi.Conn, error) {
if f > physic.GigaHertz {
return nil, fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 1.5MHz", f)
}
if f > ft232rMaxSpeed/2 {
// TODO(maruel): Figure out a way to communicate that the speed was lowered.
// https://github.com/google/periph/issues/255
f = ft232rMaxSpeed / 2
}
if f < 100*physic.Hertz {
return nil, fmt.Errorf("d2xx: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?", f)
}
if bits&7 != 0 {
return nil, errors.New("d2xx: bits must be multiple of 8")
}
if bits != 8 {
return nil, errors.New("d2xx: implement bits per word above 8")
}
s.c.f.mu.Lock()
defer s.c.f.mu.Unlock()
s.c.noCS = m&spi.NoCS != 0
s.c.halfDuplex = m&spi.HalfDuplex != 0
s.c.lsbFirst = m&spi.LSBFirst != 0
m &^= spi.NoCS | spi.HalfDuplex | spi.LSBFirst
if s.c.halfDuplex {
return nil, errors.New("d2xx: spi.HalfDuplex is not yet supported (implementing wouldn't be too hard, please submit a PR")
}
if m < 0 || m > 3 {
return nil, errors.New("d2xx: unknown spi mode")
}
s.c.edgeInvert = m&1 != 0
s.c.clkActiveLow = m&2 != 0
if s.maxFreq == 0 || f < s.maxFreq {
if err := s.c.f.SetSpeed(f * 2); err != nil {
return nil, err
}
s.maxFreq = f
}
// D0, D2 and D3 are output. D4~D7 are kept as-is.
const mosi = byte(1) << 0 // TX
const miso = byte(1) << 1 // RX
const clk = byte(1) << 2 // RTS
const cs = byte(1) << 3 // CTS
mask := mosi | clk | cs | (s.c.f.dmask & 0xF0)
if err := s.c.f.setDBusMaskLocked(mask); err != nil {
return nil, err
}
// TODO(maruel): Combine both following calls if possible. We'd shave off a
// few ms.
if !s.c.noCS {
// CTS/SPI_CS is active low.
if err := s.c.f.dbusSyncGPIOOutLocked(3, gpio.High); err != nil {
return nil, err
}
}
if s.c.clkActiveLow {
// RTS/SPI_CLK is active low.
if err := s.c.f.dbusSyncGPIOOutLocked(2, gpio.High); err != nil {
return nil, err
}
}
s.c.f.usingSPI = true
return &s.c, nil
}
// LimitSpeed implements spi.Port.
func (s *spiSyncPort) LimitSpeed(f physic.Frequency) error {
if f > physic.GigaHertz {
return fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 1.5MHz", f)
}
if f < 100*physic.Hertz {
return fmt.Errorf("d2xx: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?", f)
}
s.c.f.mu.Lock()
defer s.c.f.mu.Unlock()
if s.maxFreq != 0 && s.maxFreq <= f {
return nil
}
if err := s.c.f.SetSpeed(f * 2); err == nil {
s.maxFreq = f
}
return nil
}
// CLK returns the SCK (clock) pin.
func (s *spiSyncPort) CLK() gpio.PinOut {
return s.c.CLK()
}
// MOSI returns the SDO (master out, slave in) pin.
func (s *spiSyncPort) MOSI() gpio.PinOut {
return s.c.MOSI()
}
// MISO returns the SDI (master in, slave out) pin.
func (s *spiSyncPort) MISO() gpio.PinIn {
return s.c.MISO()
}
// CS returns the CSN (chip select) pin.
func (s *spiSyncPort) CS() gpio.PinOut {
return s.c.CS()
}
type spiSyncConn struct {
// Immutable.
f *FT232R
// Initialized at Connect().
edgeInvert bool // CPHA=1
clkActiveLow bool // CPOL=1
noCS bool // CS line is not changed
lsbFirst bool // Default is MSB first
halfDuplex bool // 3 wire mode
}
func (s *spiSyncConn) String() string {
return s.f.String()
}
func (s *spiSyncConn) Tx(w, r []byte) error {
var p = [1]spi.Packet{{W: w, R: r}}
return s.TxPackets(p[:])
}
func (s *spiSyncConn) Duplex() conn.Duplex {
// TODO(maruel): Support half if there's a need.
return conn.Full
}
func (s *spiSyncConn) TxPackets(pkts []spi.Packet) error {
// We need to 'expand' each bit 2 times * 8 bits, which leads
// to a 16x memory usage increase. Adds 5 samples before and after.
totalW := 0
totalR := 0
for _, p := range pkts {
if p.KeepCS {
return errors.New("d2xx: implement spi.Packet.KeepCS")
}
if p.BitsPerWord&7 != 0 {
return errors.New("d2xx: bits must be a multiple of 8")
}
if p.BitsPerWord != 0 && p.BitsPerWord != 8 {
return errors.New("d2xx: implement spi.Packet.BitsPerWord")
}
if err := verifyBuffers(p.W, p.R); err != nil {
return err
}
// TODO(maruel): Correctly calculate offsets.
if len(p.W) != 0 {
totalW += 2 * 8 * len(p.W)
}
if len(p.R) != 0 {
totalR += 2 * 8 * len(p.R)
}
}
// Create a large, single chunk.
var we, re []byte
if totalW != 0 {
totalW += 10
we = make([]byte, 0, totalW)
}
if totalR != 0 {
totalR += 10
re = make([]byte, totalR)
}
const mosi = byte(1) << 0 // TX
const miso = byte(1) << 1 // RX
const clk = byte(1) << 2 // RTS
const cs = byte(1) << 3 // CTS
s.f.mu.Lock()
defer s.f.mu.Unlock()
// https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#Data_transmission
csActive := s.f.dvalue & s.f.dmask & 0xF0
csIdle := csActive
if !s.noCS {
csIdle = csActive | cs
}
clkIdle := csActive
clkActive := clkIdle | clk
if s.clkActiveLow {
clkActive, clkIdle = clkIdle, clkActive
csIdle |= clk
}
// Start of tx; assert CS if needed.
we = append(we, csIdle, clkIdle, clkIdle, clkIdle, clkIdle)
for _, p := range pkts {
if len(p.W) == 0 && len(p.R) == 0 {
continue
}
// TODO(maruel): s.halfDuplex.
for _, b := range p.W {
for j := uint(0); j < 8; j++ {
// For each bit, handle clock phase and data phase.
bit := byte(0)
if !s.lsbFirst {
// MSBF
if b&(0x80>>j) != 0 {
bit = mosi
}
} else {
// LSBF
if b&(1<<j) != 0 {
bit = mosi
}
}
if !s.edgeInvert {
// Mode0/2; CPHA=0
we = append(we, clkIdle|bit, clkActive|bit)
} else {
// Mode1/3; CPHA=1
we = append(we, clkActive|bit, clkIdle|bit)
}
}
}
}
// End of tx; deassert CS.
we = append(we, clkIdle, clkIdle, clkIdle, clkIdle, csIdle)
if err := s.f.txLocked(we, re); err != nil {
return err
}
// Extract data from re into r.
for _, p := range pkts {
// TODO(maruel): Correctly calculate offsets.
if len(p.W) == 0 && len(p.R) == 0 {
continue
}
// TODO(maruel): halfDuplex.
for i := range p.R {
// For each bit, read at the right data phase.
b := byte(0)
for j := 0; j < 8; j++ {
if re[5+i*8*2+j*2+1]&byte(1)<<1 != 0 {
if !s.lsbFirst {
// MSBF
b |= 0x80 >> uint(j)
} else {
// LSBF
b |= 1 << uint(j)
}
}
}
p.R[i] = b
}
}
return nil
}
// CLK returns the SCK (clock) pin.
func (s *spiSyncConn) CLK() gpio.PinOut {
return s.f.D2 // RTS
}
// MOSI returns the SDO (master out, slave in) pin.
func (s *spiSyncConn) MOSI() gpio.PinOut {
return s.f.D0 // TX
}
// MISO returns the SDI (master in, slave out) pin.
func (s *spiSyncConn) MISO() gpio.PinIn {
return s.f.D1 // RX
}
// CS returns the CSN (chip select) pin.
func (s *spiSyncConn) CS() gpio.PinOut {
return s.f.D3 // CTS
}
//
func verifyBuffers(w, r []byte) error {
if len(w) != 0 {
if len(r) != 0 {
if len(w) != len(r) {
return errors.New("d2xx: both buffers must have the same size")
}
}
// TODO(maruel): When the buffer is >64Kb, cut it in parts and do not
// request a flush. Still try to read though.
if len(w) > 65536 {
return errors.New("d2xx: maximum buffer size is 64Kb")
}
} else if len(r) != 0 {
// TODO(maruel): Remove, this is not a problem.
if len(r) > 65536 {
return errors.New("d2xx: maximum buffer size is 64Kb")
}
}
return nil
}
var _ spi.PortCloser = &spiMPSEEPort{}
var _ spi.Conn = &spiMPSEEConn{}
var _ spi.PortCloser = &spiSyncPort{}
var _ spi.Conn = &spiSyncConn{}

4
vendor/periph.io/x/host/v3/host.go generated vendored
View File

@ -6,9 +6,7 @@ package host
import (
"periph.io/x/conn/v3/driver/driverreg"
// TODO(maruel): For now do not include ftdi by default. It's not stable
// enough to warrant being included.
// _ "periph.io/x/host/v3/ftdi"
_ "periph.io/x/host/v3/ftdi"
)
// Init calls driverreg.Init() and returns it as-is.

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm
// +build !arm
package odroidc1

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build arm64
// +build arm64
package pine64

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm && !arm64
// +build !arm,!arm64
package pine64

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !linux
// +build !linux
package pmem

View File

@ -384,7 +384,6 @@ const (
memory1GB revisionCode = 2 << memoryShift
memory2GB revisionCode = 3 << memoryShift
memory4GB revisionCode = 4 << memoryShift
memory8GB revisionCode = 5 << memoryShift
sonyUK revisionCode = 0 << manufacturerShift
egoman revisionCode = 1 << manufacturerShift
@ -414,9 +413,6 @@ const (
boardReserved revisionCode = 0xf << boardShift
boardCM3Plus revisionCode = 0x10 << boardShift
board4B revisionCode = 0x11 << boardShift
boardZero2W revisionCode = 0x12 << boardShift
board400 revisionCode = 0x13 << boardShift
boardCM4 revisionCode = 0x14 << boardShift
)
// features represents the different features on various Raspberry Pi boards.
@ -506,14 +502,6 @@ func (f *features) init(v uint32) error {
f.hdrAudio = true
f.audioLeft41 = true
f.hdrHDMI = true
case boardZero2W:
f.hdrP1P40 = true
f.hdrHDMI = true
case board400:
f.hdrP1P40 = true
f.hdrHDMI = true
case boardCM4:
// Compute Module does not have a SODIMM header.
default:
return fmt.Errorf("rpi: unknown hardware version: 0x%x", r)
}

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build arm64
// +build arm64
package rpi

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !arm && !arm64
// +build !arm,!arm64
package rpi

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !linux
// +build !linux
package sysfs

View File

@ -2,7 +2,6 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
//go:build !linux
// +build !linux
package sysfs