-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement ioctl access to Linux GPIO chips/lines.
- Loading branch information
Showing
9 changed files
with
1,964 additions
and
768 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Testing | ||
|
||
The tests implemented perform *functional* tests of the library. This means that | ||
the tests performed interact with a GPIO chipset, and perform actual read/write | ||
operations. Using this test set, it's possible to quickly and accurately check | ||
if the library is working as expected on a specific hardware/kernel combination. | ||
|
||
## Requirements | ||
|
||
Although the library is not Raspberry Pi specific, the GPIO pin names used for | ||
tests are. | ||
|
||
As written, the tests must be executed on a Raspberry Pi SBC running Linux. Tested | ||
models are: | ||
|
||
* Raspberry Pi 3B | ||
* Raspberry Pi Zero W | ||
* Raspberry Pi 4 | ||
* Raspberry Pi 5 | ||
|
||
You must also have the golang SDK installed. | ||
|
||
## Setting Up | ||
|
||
In order to execute the functional tests, you must jumper the sets of pins shown | ||
below together. | ||
|
||
For example, the single line tests require GPIO5 and GPIO13 to be connected to | ||
each other, so a jumper is required between pins 29 and 33. For the multi-line | ||
tests to work, you must connect the following GPIO pins together with jumpers. | ||
|
||
| GPIO Output | Output Pin # | GPIO Input | Input Pin # | | ||
| ----------- | ------------ | ---------- | ----------- | | ||
| GPIO2 | 3 | GPIO10 | 19 | | ||
| GPIO3 | 5 | GPIO11 | 23 | | ||
| GPIO4 | 7 | GPIO12 | 32 | | ||
| GPIO5 | 29 | GPIO13 | 33 | | ||
| GPIO6 | 31 | GPIO14 | 8 | | ||
| GPIO7 | 26 | GPIO15 | 10 | | ||
| GPIO8 | 24 | GPIO16 | 36 | | ||
| GPIO9 | 21 | GPIO17 | 11 | | ||
|
||
## Cross-Compiling | ||
If you don't have a working go installation on the target machine, you can cross | ||
compile from one machine and then copy the test binary to the target machine. | ||
|
||
To cross compile for Raspberry Pi, execute the command: | ||
|
||
```bash | ||
$periph.io/x/host/gpioctl> GOOS=linux GOARCH=arm64 go test -c | ||
$periph.io/x/host/gpioctl> scp gpioioctl.test [email protected]:~ | ||
$periph.io/x/host/gpioctl> ssh [email protected] | ||
$user> ./gpioioctl.test -test.v | ||
``` | ||
for Pi Zero W, use: | ||
|
||
```bash | ||
$periph.io/x/host/gpioctl> GOOS=linux GOARCH=arm GOARM=6 go test -c | ||
$periph.io/x/host/gpioctl> scp gpioioctl.test [email protected]:~ | ||
$periph.io/x/host/gpioctl> ssh [email protected] | ||
$user> ./gpioioctl.test -test.v | ||
|
||
``` | ||
|
||
## Executing the Tests | ||
|
||
After connecting the jumper wires as shown above, and you have golang installed | ||
and the go/bin directory in the path, change to this directory and execute the | ||
command: | ||
|
||
```bash | ||
$> go test -v -cover | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package gpioioctl_test | ||
// Copyright 2024 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. | ||
|
||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"periph.io/x/conn/v3/driver/driverreg" | ||
"periph.io/x/conn/v3/gpio" | ||
"periph.io/x/conn/v3/gpio/gpioreg" | ||
"periph.io/x/host/v3" | ||
"periph.io/x/host/v3/gpioioctl" | ||
) | ||
|
||
func ExampleChips() { | ||
_, _ = host.Init() | ||
_, _ = driverreg.Init() | ||
|
||
fmt.Println("GPIO Test Program") | ||
chip := gpioioctl.Chips[0] | ||
defer chip.Close() | ||
fmt.Println(chip.String()) | ||
// Test by flashing an LED. | ||
led := gpioreg.ByName("GPIO5") | ||
fmt.Println("Flashing LED ", led.Name()) | ||
for i := range 20 { | ||
_ = led.Out((i % 2) == 0) | ||
time.Sleep(500 * time.Millisecond) | ||
} | ||
_ = led.Out(true) | ||
|
||
testRotary(chip, "GPIO20", "GPIO21", "GPIO19") | ||
} | ||
|
||
// Test the LineSet functionality by using it to read a Rotary Encoder w/ Button. | ||
func testRotary(chip *gpioioctl.GPIOChip, stateLine, dataLine, buttonLine string) { | ||
config := gpioioctl.LineSetConfig{DefaultDirection: gpioioctl.LineInput, DefaultEdge: gpio.RisingEdge, DefaultPull: gpio.PullUp} | ||
config.Lines = []string{stateLine, dataLine, buttonLine} | ||
// The Data Pin of the Rotary Encoder should NOT have an edge. | ||
_ = config.AddOverrides(gpioioctl.LineInput, gpio.NoEdge, gpio.PullUp, dataLine) | ||
ls, err := chip.LineSetFromConfig(&config) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer ls.Close() | ||
statePinNumber := uint32(ls.ByOffset(0).Number()) | ||
buttonPinNumber := uint32(ls.ByOffset(2).Number()) | ||
|
||
var tLast = time.Now().Add(-1 * time.Second) | ||
var halting bool | ||
go func() { | ||
time.Sleep(60 * time.Second) | ||
halting = true | ||
fmt.Println("Sending halt!") | ||
_ = ls.Halt() | ||
}() | ||
fmt.Println("Test Rotary Switch - Turn dial to test rotary encoder, press button to test it.") | ||
for { | ||
lineNumber, _, err := ls.WaitForEdge(0) | ||
if err == nil { | ||
tNow := time.Now() | ||
if (tNow.UnixMilli() - tLast.UnixMilli()) < 100 { | ||
continue | ||
} | ||
tLast = tNow | ||
if lineNumber == statePinNumber { | ||
var bits uint64 | ||
tDeadline := tNow.UnixNano() + 20_000_000 | ||
var consecutive uint64 | ||
for time.Now().UnixNano() < tDeadline { | ||
// Spin on reading the pins until we get some number | ||
// of consecutive readings that are the same. | ||
bits, _ = ls.Read(0x03) | ||
if bits&0x01 == 0x00 { | ||
// We're bouncing. | ||
consecutive = 0 | ||
} else { | ||
consecutive += 1 | ||
if consecutive > 25 { | ||
if bits == 0x01 { | ||
fmt.Printf("Clockwise bits=%d\n", bits) | ||
} else if bits == 0x03 { | ||
fmt.Printf("CounterClockwise bits=%d\n", bits) | ||
} | ||
break | ||
} | ||
} | ||
} | ||
} else if lineNumber == buttonPinNumber { | ||
fmt.Println("Button Pressed!") | ||
} | ||
} else { | ||
fmt.Println("Timeout detected") | ||
if halting { | ||
break | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.