chore: bump periph.io dependencies

This commit is contained in:
Cyrille Nofficial 2022-01-02 23:37:01 +01:00
parent 0b8d2218c1
commit c1ec63fcc1
63 changed files with 506 additions and 5328 deletions

5
go.mod
View File

@ -8,8 +8,8 @@ require (
github.com/eclipse/paho.mqtt.golang v1.3.5
github.com/golang/protobuf v1.5.2
go.uber.org/zap v1.19.1
periph.io/x/conn/v3 v3.6.8
periph.io/x/host/v3 v3.7.0
periph.io/x/conn/v3 v3.6.10
periph.io/x/host/v3 v3.7.2
)
require (
@ -18,5 +18,4 @@ require (
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
)

14
go.sum
View File

@ -48,6 +48,8 @@ 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=
@ -159,10 +161,8 @@ 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.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=
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=

8
vendor/modules.txt vendored
View File

@ -65,7 +65,7 @@ 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.8
# periph.io/x/conn/v3 v3.6.10
## explicit; go 1.13
periph.io/x/conn/v3
periph.io/x/conn/v3/driver
@ -80,10 +80,7 @@ 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/d2xx v0.0.3
## explicit; go 1.13
periph.io/x/d2xx
# periph.io/x/host/v3 v3.7.0
# periph.io/x/host/v3 v3.7.2
## explicit; go 1.13
periph.io/x/host/v3
periph.io/x/host/v3/allwinner
@ -96,7 +93,6 @@ 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,62 +17,87 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
# Test in advance: host
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- -t
- ./...
- dir: ../host
cmd:
- go
- test
- -short
- ./...
dir: ../host
# Test in advance.
- cmd:
# Test in advance: devices
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- -t
- ./...
- dir: ../devices
cmd:
- go
- test
- -short
- ./...
dir: ../devices
# Test in advance.
- cmd:
# Test in advance: cmd
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- -t
- ./...
- dir: ../cmd
cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- cmd:
- dir: ../cmd
cmd:
- go
- install
- -v
@ -81,7 +106,6 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -111,62 +135,87 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
# Test in advance: host
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- -t
- ./...
- dir: ../host
cmd:
- go
- test
- -short
- ./...
dir: ../host
# Test in advance.
- cmd:
# Test in advance: devices
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- -t
- ./...
- dir: ../devices
cmd:
- go
- test
- -short
- ./...
dir: ../devices
# Test in advance.
- cmd:
# Test in advance: cmd
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- -t
- ./...
- dir: ../cmd
cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- cmd:
- dir: ../cmd
cmd:
- go
- install
- -v
@ -176,7 +225,6 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -219,62 +267,87 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
# Test in advance: host
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- -t
- ./...
- dir: ../host
cmd:
- go
- test
- -short
- ./...
dir: ../host
# Test in advance.
- cmd:
# Test in advance: devices
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- -t
- ./...
- dir: ../devices
cmd:
- go
- test
- -short
- ./...
dir: ../devices
# Test in advance.
- cmd:
# Test in advance: cmd
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- -t
- ./...
- dir: ../cmd
cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- cmd:
- dir: ../cmd
cmd:
- go
- install
- -v
@ -284,7 +357,6 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -343,62 +415,87 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
# Test in advance: host
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- -t
- ./...
- dir: ../host
cmd:
- go
- test
- -short
- ./...
dir: ../host
# Test in advance.
- cmd:
# Test in advance: devices
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- -t
- ./...
- dir: ../devices
cmd:
- go
- test
- -short
- ./...
dir: ../devices
# Test in advance.
- cmd:
# Test in advance: cmd
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- -t
- ./...
- dir: ../cmd
cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- cmd:
- dir: ../cmd
cmd:
- go
- install
- -v
@ -408,7 +505,6 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
@ -433,62 +529,87 @@ workers:
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
# Test in advance: host
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/host
dir: ..
- cmd:
- dir: ../host
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../host
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../host
- cmd:
- -t
- ./...
- dir: ../host
cmd:
- go
- test
- -short
- ./...
dir: ../host
# Test in advance.
- cmd:
# Test in advance: devices
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- dir: ../devices
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../devices
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../devices
- cmd:
- -t
- ./...
- dir: ../devices
cmd:
- go
- test
- -short
- ./...
dir: ../devices
# Test in advance.
- cmd:
# Test in advance: cmd
- dir: ..
cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- dir: ../cmd
cmd:
- go
- mod
- edit
- -replace=periph.io/x/conn/v3=../conn
- dir: ../cmd
cmd:
- go
- get
- periph.io/x/conn/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- -t
- ./...
- dir: ../cmd
cmd:
- go
- test
- -short
- ./...
dir: ../cmd
# Test commands.
- cmd:
- dir: ../cmd
cmd:
- go
- install
- -v
@ -498,7 +619,6 @@ workers:
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:

View File

@ -9,8 +9,7 @@ get an [invite here](https://invite.slack.golangbridge.org/).
[![mascot](https://raw.githubusercontent.com/periph/website/master/site/static/img/periph-mascot-280.png)](https://periph.io/)
[![PkgGoDev](https://pkg.go.dev/badge/periph.io/x/conn/v3)](https://pkg.go.dev/periph.io/x/conn/v3)
[![Coverage
Status](https://codecov.io/gh/periph/conn/graph/badge.svg)](https://codecov.io/gh/periph/conn)
[![codecov](https://codecov.io/gh/periph/conn/branch/main/graph/badge.svg?token=1WIDCAJIK8)](https://codecov.io/gh/periph/conn)
## Example

View File

@ -5,6 +5,7 @@
// 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
@ -50,9 +51,11 @@ func initImpl() (*State, error) {
if err != nil {
return state, err
}
loaded := make(map[string]struct{}, len(byName))
loaded := sync.Map{}
for _, s := range stages {
s.loadParallel(loaded, cD, cS, cE)
// It's very important that each of the stage is fully completed before the
// next one is attempted.
s.loadParallel(&loaded, cD, cS, cE)
}
close(cD)
close(cS)
@ -61,10 +64,9 @@ func initImpl() (*State, error) {
return state, nil
}
// loadParallel loads all the drivers for this stage in parallel.
//
// Updates loaded in a safe way.
func (s *stage) loadParallel(loaded map[string]struct{}, cD chan<- driver.Impl, cS, cE chan<- DriverFailure) {
// 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) {
success := make(chan string)
go func() {
defer close(success)
@ -73,7 +75,7 @@ func (s *stage) loadParallel(loaded map[string]struct{}, cD chan<- driver.Impl,
for name, drv := range s.drvs {
// Intentionally do not look at After(), only Prerequisites().
for _, dep := range drv.Prerequisites() {
if _, ok := loaded[dep]; !ok {
if _, ok := loaded.Load(dep); !ok {
cS <- DriverFailure{drv, errors.New("dependency not loaded: " + strconv.Quote(dep))}
continue loop
}
@ -98,6 +100,6 @@ func (s *stage) loadParallel(loaded map[string]struct{}, cD chan<- driver.Impl,
wg.Wait()
}()
for s := range success {
loaded[s] = struct{}{}
loaded.Store(s, nil)
}
}

View File

@ -5,6 +5,7 @@
// 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
View File

@ -1,48 +0,0 @@
# 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
View File

@ -1,202 +0,0 @@
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
View File

@ -1,44 +0,0 @@
# 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
View File

@ -1,145 +0,0 @@
// 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)
}

View File

@ -1,13 +0,0 @@
// 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"

View File

@ -1,13 +0,0 @@
// 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"

View File

@ -1,16 +0,0 @@
// 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"

View File

@ -1,13 +0,0 @@
// 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
View File

@ -1,219 +0,0 @@
// 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)
}

View File

@ -1,109 +0,0 @@
// 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
}

View File

@ -1,19 +0,0 @@
// 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"

View File

@ -1,281 +0,0 @@
// 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
View File

@ -1,18 +0,0 @@
// 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
View File

@ -1,39 +0,0 @@
// 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
View File

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

View File

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

View File

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

View File

@ -2,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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

@ -1,878 +0,0 @@
// 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)

View File

@ -1,20 +0,0 @@
// 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

View File

@ -1,213 +0,0 @@
// 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

View File

@ -1,368 +0,0 @@
// 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]]
}

View File

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

View File

@ -1,241 +0,0 @@
// 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{}

View File

@ -1,382 +0,0 @@
// 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())
}

View File

@ -1,295 +0,0 @@
// 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{}

View File

@ -1,452 +0,0 @@
// 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)
}

View File

@ -1,205 +0,0 @@
// 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{}

View File

@ -1,85 +0,0 @@
// 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{}

View File

@ -1,697 +0,0 @@
// 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,7 +6,9 @@ package host
import (
"periph.io/x/conn/v3/driver/driverreg"
_ "periph.io/x/host/v3/ftdi"
// 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"
)
// Init calls driverreg.Init() and returns it as-is.

View File

@ -2,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +384,7 @@ 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
@ -413,6 +414,9 @@ 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.
@ -502,6 +506,14 @@ 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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,6 +2,7 @@
// 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