i2c: improve docs and test coverage for PCA9685
Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
parent
876ada9aa7
commit
1fe7469a1c
|
@ -25,6 +25,8 @@ const (
|
|||
PCA9685_ALLLED_OFF_H = 0xFD
|
||||
)
|
||||
|
||||
// PCA9685Driver is a Gobot Driver for the PCA9685 16-channel 12-bit
|
||||
// PWM/Servo controller.
|
||||
type PCA9685Driver struct {
|
||||
name string
|
||||
connector Connector
|
||||
|
@ -41,76 +43,67 @@ type PCA9685Driver struct {
|
|||
// i2c.WithAddress(int): address to use with this driver
|
||||
//
|
||||
func NewPCA9685Driver(a Connector, options ...func(Config)) *PCA9685Driver {
|
||||
m := &PCA9685Driver{
|
||||
p := &PCA9685Driver{
|
||||
name: gobot.DefaultName("PCA9685"),
|
||||
connector: a,
|
||||
Config: NewConfig(),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(m)
|
||||
option(p)
|
||||
}
|
||||
|
||||
// TODO: add commands for API
|
||||
return m
|
||||
return p
|
||||
}
|
||||
|
||||
// Name returns the Name for the Driver
|
||||
func (h *PCA9685Driver) Name() string { return h.name }
|
||||
func (p *PCA9685Driver) Name() string { return p.name }
|
||||
|
||||
// SetName sets the Name for the Driver
|
||||
func (h *PCA9685Driver) SetName(n string) { h.name = n }
|
||||
func (p *PCA9685Driver) SetName(n string) { p.name = n }
|
||||
|
||||
// Connection returns the connection for the Driver
|
||||
func (h *PCA9685Driver) Connection() gobot.Connection { return h.connector.(gobot.Connection) }
|
||||
func (p *PCA9685Driver) Connection() gobot.Connection { return p.connector.(gobot.Connection) }
|
||||
|
||||
// Start initializes the pca9685
|
||||
func (h *PCA9685Driver) Start() (err error) {
|
||||
bus := h.GetBusOrDefault(h.connector.GetDefaultBus())
|
||||
address := h.GetAddressOrDefault(pca9685Address)
|
||||
func (p *PCA9685Driver) Start() (err error) {
|
||||
bus := p.GetBusOrDefault(p.connector.GetDefaultBus())
|
||||
address := p.GetAddressOrDefault(pca9685Address)
|
||||
|
||||
h.connection, err = h.connector.GetConnection(address, bus)
|
||||
p.connection, err = p.connector.GetConnection(address, bus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := h.connection.Write([]byte{PCA9685_MODE1, 0x00}); err != nil {
|
||||
if _, err := p.connection.Write([]byte{PCA9685_MODE1, 0x00}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := h.connection.Write([]byte{PCA9685_ALLLED_OFF_H, 0x10}); err != nil {
|
||||
if _, err := p.connection.Write([]byte{PCA9685_ALLLED_OFF_H, 0x10}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Halt returns true if devices is halted successfully
|
||||
func (h *PCA9685Driver) Halt() (err error) { return }
|
||||
|
||||
// SetPWM sets the channel to whichever pwm setting from 0-4096
|
||||
func (h *PCA9685Driver) SetPWM(channel int, on uint16, off uint16) (err error) {
|
||||
if _, err := h.connection.Write([]byte{byte(PCA9685_LED0_ON_L + 4*channel), byte(on), byte(on >> 8), byte(off), byte(off >> 8)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if _, err := h.connection.Write([]byte{byte(PCA9685_LED0_ON_L + 4*channel), byte(on & 0xff)}); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if _, err := h.connection.Write([]byte{byte(PCA9685_LED0_ON_H + 4*channel), byte(on >> 8)}); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if _, err := h.connection.Write([]byte{byte(PCA9685_LED0_OFF_L + 4*channel), byte(off & 0xff)}); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if _, err := h.connection.Write([]byte{byte(PCA9685_LED0_OFF_H + 4*channel), byte(off >> 8)}); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// Halt stops the device
|
||||
func (p *PCA9685Driver) Halt() (err error) {
|
||||
_, err = p.connection.Write([]byte{PCA9685_ALLLED_OFF_H, 0x10})
|
||||
return
|
||||
}
|
||||
|
||||
func (h *PCA9685Driver) SetPWMFreq(freq float32) error {
|
||||
// Correct for overshoot in the frequency setting (see issue #11).
|
||||
// SetPWM sets a specific channel to a pwm value from 0-4096
|
||||
func (p *PCA9685Driver) SetPWM(channel int, on uint16, off uint16) (err error) {
|
||||
if _, err := p.connection.Write([]byte{byte(PCA9685_LED0_ON_L + 4*channel), byte(on), byte(on >> 8), byte(off), byte(off >> 8)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SetPWMFreq sets the PWM frequency in Hz
|
||||
func (p *PCA9685Driver) SetPWMFreq(freq float32) error {
|
||||
freq *= 0.9
|
||||
|
||||
var prescalevel float32 = 25000000
|
||||
|
@ -119,50 +112,53 @@ func (h *PCA9685Driver) SetPWMFreq(freq float32) error {
|
|||
prescalevel -= 1
|
||||
prescale := byte(prescalevel + 0.5)
|
||||
|
||||
if _, err := h.connection.Write([]byte{byte(PCA9685_MODE1)}); err != nil {
|
||||
if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1)}); err != nil {
|
||||
return err
|
||||
}
|
||||
data := make([]byte, 1)
|
||||
oldmode, err := h.connection.Read(data)
|
||||
oldmode, err := p.connection.Read(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newmode := (oldmode & 0x7F) | 0x10 // sleep
|
||||
if _, err := h.connection.Write([]byte{byte(PCA9685_MODE1), byte(newmode)}); err != nil {
|
||||
newmode := (oldmode & 0x7F) | 0x10
|
||||
if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(newmode)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := h.connection.Write([]byte{byte(PCA9685_PRESCALE), prescale}); err != nil {
|
||||
if _, err := p.connection.Write([]byte{byte(PCA9685_PRESCALE), prescale}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := h.connection.Write([]byte{byte(PCA9685_MODE1), byte(oldmode)}); err != nil {
|
||||
if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(oldmode)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if _, err := h.connection.Write([]byte{byte(PCA9685_MODE1), byte(oldmode | 0xa1)}); err != nil {
|
||||
if _, err := p.connection.Write([]byte{byte(PCA9685_MODE1), byte(oldmode | 0xa1)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *PCA9685Driver) PwmWrite(pin string, val byte) (err error) {
|
||||
// PwmWrite writes a PWM signal to the specified pin
|
||||
func (p *PCA9685Driver) PwmWrite(pin string, val byte) (err error) {
|
||||
i, err := strconv.Atoi(pin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
v := gobot.ToScale(gobot.FromScale(float64(val), 0, 255), 0, 4096)
|
||||
return h.SetPWM(i, 0, uint16(v))
|
||||
return p.SetPWM(i, 0, uint16(v))
|
||||
}
|
||||
|
||||
func (h *PCA9685Driver) ServoWrite(pin string, val byte) (err error) {
|
||||
// ServoWrite writes a servo signal to the specified pin.
|
||||
// Valid values are from 0-180.
|
||||
func (p *PCA9685Driver) ServoWrite(pin string, val byte) (err error) {
|
||||
i, err := strconv.Atoi(pin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
v := gobot.ToScale(gobot.FromScale(float64(val), 0, 180), 200, 500)
|
||||
return h.SetPWM(i, 0, uint16(v))
|
||||
return p.SetPWM(i, 0, uint16(v))
|
||||
}
|
||||
|
|
|
@ -73,21 +73,56 @@ func TestPCA9685DriverStartWriteError(t *testing.T) {
|
|||
|
||||
func TestPCA9685DriverHalt(t *testing.T) {
|
||||
pca := initTestPCA9685Driver()
|
||||
|
||||
gobottest.Assert(t, pca.Start(), nil)
|
||||
gobottest.Assert(t, pca.Halt(), nil)
|
||||
}
|
||||
|
||||
// func TestPCA9685DriverWriteData(t *testing.T) {
|
||||
// pca, adaptor := initTestPCA9685DriverWithStubbedAdaptor()
|
||||
//
|
||||
// adaptor.i2cReadImpl = func(b []byte) (int, error) {
|
||||
// copy(b, []byte{0x00, 0x01, 0x02, 0x04})
|
||||
// return 4, nil
|
||||
// }
|
||||
// pca.Start()
|
||||
// mpu.GetData()
|
||||
// gobottest.Assert(t, mpu.Temperature, int16(36))
|
||||
// }
|
||||
func TestPCA9685DriverSetPWM(t *testing.T) {
|
||||
pca := initTestPCA9685Driver()
|
||||
gobottest.Assert(t, pca.Start(), nil)
|
||||
gobottest.Assert(t, pca.SetPWM(0, 0, 256), nil)
|
||||
}
|
||||
|
||||
func TestPCA9685DriverSetPWMError(t *testing.T) {
|
||||
pca, adaptor := initTestPCA9685DriverWithStubbedAdaptor()
|
||||
gobottest.Assert(t, pca.Start(), nil)
|
||||
|
||||
adaptor.i2cWriteImpl = func([]byte) (int, error) {
|
||||
return 0, errors.New("write error")
|
||||
}
|
||||
gobottest.Assert(t, pca.SetPWM(0, 0, 256), errors.New("write error"))
|
||||
}
|
||||
|
||||
func TestPCA9685DriverSetPWMFreq(t *testing.T) {
|
||||
pca, adaptor := initTestPCA9685DriverWithStubbedAdaptor()
|
||||
gobottest.Assert(t, pca.Start(), nil)
|
||||
|
||||
adaptor.i2cReadImpl = func(b []byte) (int, error) {
|
||||
copy(b, []byte{0x01})
|
||||
return 1, nil
|
||||
}
|
||||
gobottest.Assert(t, pca.SetPWMFreq(60), nil)
|
||||
}
|
||||
|
||||
func TestPCA9685DriverSetPWMFreqReadError(t *testing.T) {
|
||||
pca, adaptor := initTestPCA9685DriverWithStubbedAdaptor()
|
||||
gobottest.Assert(t, pca.Start(), nil)
|
||||
|
||||
adaptor.i2cReadImpl = func(b []byte) (int, error) {
|
||||
return 0, errors.New("read error")
|
||||
}
|
||||
gobottest.Assert(t, pca.SetPWMFreq(60), errors.New("read error"))
|
||||
}
|
||||
|
||||
func TestPCA9685DriverSetPWMFreqWriteError(t *testing.T) {
|
||||
pca, adaptor := initTestPCA9685DriverWithStubbedAdaptor()
|
||||
gobottest.Assert(t, pca.Start(), nil)
|
||||
|
||||
adaptor.i2cWriteImpl = func([]byte) (int, error) {
|
||||
return 0, errors.New("write error")
|
||||
}
|
||||
gobottest.Assert(t, pca.SetPWMFreq(60), errors.New("write error"))
|
||||
}
|
||||
|
||||
func TestPCA9685DriverSetName(t *testing.T) {
|
||||
pca := initTestPCA9685Driver()
|
||||
|
|
Loading…
Reference in New Issue