Skip to content

Commit

Permalink
feat: Also support generic CDEV GPIO devices alongside RPI
Browse files Browse the repository at this point in the history
  • Loading branch information
MikMuellerDev committed Sep 2, 2023
1 parent ba840ff commit 7ee2a74
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 39 deletions.
9 changes: 8 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,11 @@ module github.com/smarthome-go/rpirf

go 1.17

require github.com/stianeikeland/go-rpio/v4 v4.6.0
require (
github.com/stianeikeland/go-rpio/v4 v4.6.0
github.com/warthog618/gpiod v0.8.2
)

require golang.org/x/sys v0.10.0 // indirect

replace rpirf => ../rpirf/
44 changes: 44 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,46 @@
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/pilebones/go-udev v0.9.0/go.mod h1:T2eI2tUSK0hA2WS5QLjXJUfQkluZQu+18Cqvem3CaXI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stianeikeland/go-rpio/v4 v4.6.0 h1:eAJgtw3jTtvn/CqwbC82ntcS+dtzUTgo5qlZKe677EY=
github.com/stianeikeland/go-rpio/v4 v4.6.0/go.mod h1:A3GvHxC1Om5zaId+HqB3HKqx4K/AqeckxB7qRjxMK7o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/warthog618/config v0.5.1/go.mod h1:6Fux1X42nlCKzdwP3iloUvHtBCZYa+lalHHO9V0arHE=
github.com/warthog618/go-gpiosim v0.1.0 h1:2rTMTcKUVZxpUuvRKsagnKAbKpd3Bwffp87xywEDVGI=
github.com/warthog618/go-gpiosim v0.1.0/go.mod h1:Ngx/LYI5toxHr4E+Vm6vTgCnt0of0tktsSuMUEJ2wCI=
github.com/warthog618/gpiod v0.8.1/go.mod h1:A7v1hGR2eTsnkN+e9RoAPYgJG9bLJWtwyIIK+pgqC7s=
github.com/warthog618/gpiod v0.8.2 h1:2HgQ9pNowPp7W77sXhX5ut5Tqq1WoS3t7bXYDxtYvxc=
github.com/warthog618/gpiod v0.8.2/go.mod h1:O7BNpHjCn/4YS5yFVmoFZAlY1LuYuQ8vhPf0iy/qdi4=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
72 changes: 37 additions & 35 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ package rpirf

import (
"fmt"
"runtime"
"time"

"github.com/stianeikeland/go-rpio/v4"
Expand All @@ -23,28 +22,16 @@ import (
// Initializes the GPIO device
// Provide a pin number, a protocol, how often the signal should be sent, the pulse length and the data length
// The pin number will be the `BCM / bcm2835` pin, not the physical one
func NewRF(pinNumber uint8, protocolIndex uint8, repeat uint8, pulseLength uint16, length uint8) (RFDevice, error) {
// If the architecture is not arm, the library can not run (not a Raspberry Pi)
if runtime.GOARCH != "arm" {
return RFDevice{}, ErrNonArm
}
if err := rpio.Open(); err != nil {
// If the memory range from /dev/mem could not be opened, return the failed to initialize error
return RFDevice{}, ErrInitialize
}
// Initialize the bcm2835 pin
pin := rpio.Pin(pinNumber)
// Set pin as output
pin.Output()
func NewRF(hardware HardwareOutput, protocolIndex uint8, repeat uint8, pulseLength uint16, length uint8) RFDevice {
device := RFDevice{
Pin: pin,
Output: hardware,
TxEnabled: true,
TxProto: protocolIndex - 1,
TxRepeat: repeat,
TxLength: length,
TxPulseLength: pulseLength,
}
return device, nil
return device
}

// Disables the transmitter and frees the allocated GPIO pin
Expand All @@ -65,56 +52,71 @@ func (device *RFDevice) Send(code int) error {
return ErrNotInitialized
}
binary := fmt.Sprintf("%0*b", device.TxLength+2, code)[2:]

if code > 16777216 {
device.TxLength = 32
}
device.sendBinary(binary)
return nil

return device.sendBinary(binary)
}

// Sends the preprocessed binary code
func (device *RFDevice) sendBinary(code string) {
func (device *RFDevice) sendBinary(code string) error {
for i := 0; i < int(device.TxRepeat); i++ {
for b := 0; b < int(device.TxLength); b++ {
if len(code) > b && code[b] == '0' {
device.txL0()
if err := device.txL0(); err != nil {
return err
}
} else {
device.txL1()
if err := device.txL1(); err != nil {
return err
}
}
}
device.txSync()
if err := device.txSync(); err != nil {
return err
}
time.Sleep(time.Microsecond)
}

return nil
}

// Send a `0` bit
func (device *RFDevice) txL0() {
device.txWaveform(protocols[device.TxProto].ZeroHigh, protocols[device.TxProto].ZeroLow)
func (device *RFDevice) txL0() error {
return device.txWaveform(protocols[device.TxProto].ZeroHigh, protocols[device.TxProto].ZeroLow)
}

// Send a `1` bit
func (device *RFDevice) txL1() {
device.txWaveform(protocols[device.TxProto].OneHigh, protocols[device.TxProto].OneLow)
func (device *RFDevice) txL1() error {
return device.txWaveform(protocols[device.TxProto].OneHigh, protocols[device.TxProto].OneLow)
}

// Send a sync
func (device *RFDevice) txSync() {
device.txWaveform(protocols[device.TxProto].SyncHigh, protocols[device.TxProto].SyncLow)
func (device *RFDevice) txSync() error {
return device.txWaveform(protocols[device.TxProto].SyncHigh, protocols[device.TxProto].SyncLow)
}

// Sends a generic waveform
func (device *RFDevice) txWaveform(highPulses uint8, lowPulses uint8) {
device.Pin.High()
device.sleep((float64(highPulses) * float64(device.TxPulseLength)) / 1000000)
device.Pin.Low()
func (device *RFDevice) txWaveform(highPulses uint8, lowPulses uint8) error {
if err := device.Output.High(); err != nil {
return err
}
device.sleep((float64(highPulses) * float64(device.TxPulseLength)) / 1_000_000)
if err := device.Output.Low(); err != nil {
return err
}
device.sleep((float64(lowPulses) * float64(device.TxPulseLength)) / 1000000)

return nil
}

// customized sleep function
func (device *RFDevice) sleep(delay float64) {
newDelay := delay / 100
end := float64(time.Now().UnixMicro())/float64(1000000) + delay - newDelay
for float64(time.Now().UnixMicro())/float64(1000000) < end {
time.Sleep(time.Microsecond * time.Duration((newDelay)*100000))
end := float64(time.Now().UnixMicro())/float64(1_000_000) + delay - newDelay
for float64(time.Now().UnixMicro())/float64(1_000_000) < end {
time.Sleep(time.Microsecond * time.Duration((newDelay)*100_000))
}
}
88 changes: 88 additions & 0 deletions output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package rpirf

import (
"runtime"

"github.com/stianeikeland/go-rpio/v4"
"github.com/warthog618/gpiod"
)

type HardwareOutputKind uint8

const (
HardwareOutputRpi HardwareOutputKind = iota
HardwareOutputCdev
)

type HardwareOutput interface {
Kind() HardwareOutputKind
Low() error
High() error
}

type HardwareOutputRaspberryPi struct {
Pin rpio.Pin
}

func (self HardwareOutputRaspberryPi) Kind() HardwareOutputKind {
return HardwareOutputRpi
}

func (self HardwareOutputRaspberryPi) Low() error {
self.Pin.Low()
return nil
}

func (self HardwareOutputRaspberryPi) High() error {
self.Pin.High()
return nil
}

func NewRaspberryPi(pinNumber uint) (HardwareOutputRaspberryPi, error) {
// If the architecture is not arm, the library can not run (not a Raspberry Pi)
if runtime.GOARCH != "arm" {
return HardwareOutputRaspberryPi{}, ErrNonArm
}

if err := rpio.Open(); err != nil {
// If the memory range from /dev/mem could not be opened, return the failed to initialize error
return HardwareOutputRaspberryPi{}, ErrInitialize
}

// Initialize the bcm pin
pin := rpio.Pin(pinNumber)

// Set pin as output
pin.Output()

return HardwareOutputRaspberryPi{
Pin: pin,
}, nil
}

type HardwareOutputCharacterdev struct {
LineHandle *gpiod.Line
}

func (self HardwareOutputCharacterdev) Kind() HardwareOutputKind {
return HardwareOutputCdev
}

func (self HardwareOutputCharacterdev) Low() error {
return self.LineHandle.SetValue(0)
}

func (self HardwareOutputCharacterdev) High() error {
return self.LineHandle.SetValue(1)
}

func NewCharacterDev(devicePath string, pinNumber int) (HardwareOutputCharacterdev, error) {
out, err := gpiod.RequestLine(devicePath, pinNumber, gpiod.AsOutput(0))
if err != nil {
return HardwareOutputCharacterdev{}, err
}

return HardwareOutputCharacterdev{
LineHandle: out,
}, nil
}
4 changes: 1 addition & 3 deletions static.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package rpirf

import (
"errors"

"github.com/stianeikeland/go-rpio/v4"
)

type Protocol struct {
Expand All @@ -17,7 +15,7 @@ type Protocol struct {
}

type RFDevice struct {
Pin rpio.Pin
Output HardwareOutput
TxEnabled bool
TxProto uint8
TxRepeat uint8
Expand Down

0 comments on commit 7ee2a74

Please sign in to comment.