Skip to content

Commit

Permalink
i2c(PCA9685, adafruit): clean up architecture and fix init
Browse files Browse the repository at this point in the history
  • Loading branch information
gen2thomas committed Oct 29, 2023
1 parent 991af9a commit 4eda24a
Show file tree
Hide file tree
Showing 14 changed files with 1,037 additions and 1,005 deletions.
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ linters:
- exhaustruct # useful with some exclusions for existing code (e.g. mavlink/common/common.go)
- funlen # useful with some tweeks (reduce bugs, simplify code, better understandable code)
- gci # useful (improve readability)
- gochecknoinits # useful (reduce bugs, simplify bug catching)
- gocognit # useful with some tweeks (better understandable code)
- goconst # useful (reduce bugs)
- gocritic # useful with some exclusions for existing code (e.g. mavlink/common/common.go)
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,9 @@ Support for devices that use Inter-Integrated Circuit (I2C) have a shared set of
drivers provided using the `gobot/drivers/i2c` package:

- [I2C](https://en.wikipedia.org/wiki/I%C2%B2C) <=> [Drivers](https://github.com/hybridgroup/gobot/tree/master/drivers/i2c)
- Adafruit 2x16 RGB-LCD with 5 keys
- Adafruit Motor Hat
- Adafruit 1109 2x16 RGB-LCD with 5 keys
- Adafruit 2327 16-Channel PWM/Servo HAT Hat
- Adafruit 2348 DC and Stepper Motor Hat
- ADS1015 Analog to Digital Converter
- ADS1115 Analog to Digital Converter
- ADXL345 Digital Accelerometer
Expand Down
5 changes: 3 additions & 2 deletions drivers/i2c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/r

Gobot has a extensible system for connecting to hardware devices. The following i2c devices are currently supported:

- Adafruit 2x16 RGB-LCD with 5 keys
- Adafruit Motor Hat
- Adafruit 1109 2x16 RGB-LCD with 5 keys
- Adafruit 2327 16-Channel PWM/Servo HAT Hat
- Adafruit 2348 DC and Stepper Motor Hat
- ADS1015 Analog to Digital Converter
- ADS1115 Analog to Digital Converter
- ADXL345 Digital Accelerometer
Expand Down
45 changes: 45 additions & 0 deletions drivers/i2c/adafruit2327_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package i2c

import (
"gobot.io/x/gobot/v2"
)

// Adafruit2327Driver is a driver for Adafruit 16-Channel PWM/Servo HAT & Bonnet - a Raspberry Pi add-on, based on
// PCA9685. This driver just wraps the PCA9685Driver.
// Stacking 62 of them is possible (addresses 0x40..0x7E), for controlling up to 992 servos.
// datasheet:
// https://cdn-learn.adafruit.com/downloads/pdf/adafruit-16-channel-pwm-servo-hat-for-raspberry-pi.pdf
type Adafruit2327Driver struct {
*PCA9685Driver
}

// NewAdafruit2327Driver initializes a new driver for PWM servos.
// Params:
//
// c Connector - the Adaptor to use with this Driver
//
// Optional params:
//
// i2c.WithBus(int): bus to use with this driver
// i2c.WithAddress(int): address to use with this driver
func NewAdafruit2327Driver(c Connector, options ...func(Config)) *Adafruit2327Driver {
pca := NewPCA9685Driver(c, options...) // the default address of the driver is already 0x40
pca.SetName(gobot.DefaultName("Adafruit2327ServoHat"))
d := &Adafruit2327Driver{
PCA9685Driver: pca,
}

// TODO: add API funcs
return d
}

// SetServoMotorFreq sets the frequency for the currently addressed PWM Servo HAT.
func (a *Adafruit2327Driver) SetServoMotorFreq(freq float64) error {
return a.SetPWMFreq(float32(freq))
}

// SetServoMotorPulse is a convenience function to specify the 'tick' value,
// between 0-4095, when the signal will turn on, and when it will turn off.
func (a *Adafruit2327Driver) SetServoMotorPulse(channel byte, on, off int32) error {
return a.SetPWM(int(channel), uint16(on), uint16(off))
}
94 changes: 94 additions & 0 deletions drivers/i2c/adafruit2327_driver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package i2c

import (
"errors"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"gobot.io/x/gobot/v2"
)

// this ensures that the implementation implements the gobot.Driver interface
var _ gobot.Driver = (*Adafruit2327Driver)(nil)

func initTestAdafruit2327WithStubbedAdaptor() (*Adafruit2327Driver, *i2cTestAdaptor) {
a := newI2cTestAdaptor()
d := NewAdafruit2327Driver(a)
if err := d.Start(); err != nil {
panic(err)
}
return d, a
}

func TestNewAdafruit2327Driver(t *testing.T) {
// arrange & act
d := NewAdafruit2327Driver(newI2cTestAdaptor())
// assert
assert.IsType(t, &Adafruit2327Driver{}, d)
assert.True(t, strings.HasPrefix(d.Name(), "Adafruit2327ServoHat"))
assert.Equal(t, 0x40, d.defaultAddress)
}

func TestAdafruit2327Options(t *testing.T) {
// This is a general test, that options are applied in constructor by using the common WithBus() option and
// least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)".
// arrange & act
d := NewAdafruit2327Driver(newI2cTestAdaptor(), WithBus(2))
// assert
assert.Equal(t, 2, d.GetBusOrDefault(1))
}

func TestAdafruit2327SetServoMotorFreq(t *testing.T) {
// arrange
d, a := initTestAdafruit2327WithStubbedAdaptor()
a.written = []byte{} // reset writes of former test
const freq = 60.0
// act
err := d.SetServoMotorFreq(freq)
// assert
assert.NoError(t, err)
assert.Equal(t, 9, len(a.written)) // detailed test, see "TestPCA9685SetPWMFreq"
}

func TestAdafruit2327SetServoMotorFreqError(t *testing.T) {
// arrange
d, a := initTestAdafruit2327WithStubbedAdaptor()
a.i2cWriteImpl = func([]byte) (int, error) {
return 0, errors.New("write error")
}
const freq = 60.0
// act & assert
assert.ErrorContains(t, d.SetServoMotorFreq(freq), "write error")
}

func TestAdafruit2327SetServoMotorPulse(t *testing.T) {
// arrange
d, a := initTestAdafruit2327WithStubbedAdaptor()
a.written = []byte{} // reset writes of former test
const (
channel byte = 7
on int32 = 1234
off int32 = 4321
)
// act
err := d.SetServoMotorPulse(channel, on, off)
// assert
assert.NoError(t, err)
assert.Equal(t, 8, len(a.written)) // detailed test, see "TestPCA9685SetPWM"
}

func TestAdafruit2327SetServoMotorPulseError(t *testing.T) {
// arrange
d, a := initTestAdafruit2327WithStubbedAdaptor()
a.i2cWriteImpl = func([]byte) (int, error) {
return 0, errors.New("write error")
}
const (
channel byte = 7
on int32 = 1234
off int32 = 4321
)
// act & assert
assert.ErrorContains(t, d.SetServoMotorPulse(channel, on, off), "write error")
}
Loading

0 comments on commit 4eda24a

Please sign in to comment.