mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-29 13:49:14 +08:00
259 lines
6.5 KiB
Go
259 lines
6.5 KiB
Go
![]() |
package i2c
|
||
|
|
||
|
import (
|
||
|
"gobot.io/x/gobot"
|
||
|
)
|
||
|
|
||
|
// DRV2605Mode - operating mode
|
||
|
type DRV2605Mode uint8
|
||
|
|
||
|
// Operating modes, for use in SetMode()
|
||
|
const (
|
||
|
DRV2605ModeIntTrig DRV2605Mode = 0x00
|
||
|
DRV2605ModeExtTrigEdge = 0x01
|
||
|
DRV2605ModeExtTrigLvl = 0x02
|
||
|
DRV2605ModePWMAnalog = 0x03
|
||
|
DRV2605ModeAudioVibe = 0x04
|
||
|
DRV2605ModeRealtime = 0x05
|
||
|
DRV2605ModeDiagnose = 0x06
|
||
|
DRV2605ModeAutocal = 0x07
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
drv2605Address = 0x5A
|
||
|
|
||
|
drv2605RegStatus = 0x00
|
||
|
drv2605RegMode = 0x01
|
||
|
|
||
|
drv2605Standby = 0x40
|
||
|
|
||
|
drv2605RegRTPin = 0x02
|
||
|
drv2605RegLibrary = 0x03
|
||
|
drv2605RegWaveSeq1 = 0x04
|
||
|
drv2605RegWaveSeq2 = 0x05
|
||
|
drv2605RegWaveSeq3 = 0x06
|
||
|
drv2605RegWaveSeq4 = 0x07
|
||
|
drv2605RegWaveSeq5 = 0x08
|
||
|
drv2605RegWaveSeq6 = 0x09
|
||
|
drv2605RegWaveSeq7 = 0x0A
|
||
|
drv2605RegWaveSeq8 = 0x0B
|
||
|
|
||
|
drv2605RegGo = 0x0C
|
||
|
drv2605RegOverdrive = 0x0D
|
||
|
drv2605RegSustainPos = 0x0E
|
||
|
drv2605RegSustainNeg = 0x0F
|
||
|
drv2605RegBreak = 0x10
|
||
|
drv2605RegAudioCtrl = 0x11
|
||
|
drv2605RegAudioMinLevel = 0x12
|
||
|
drv2605RegAudioMaxLevel = 0x13
|
||
|
drv2605RegAudioMinDrive = 0x14
|
||
|
drv2605RegAudioMaxDrive = 0x15
|
||
|
drv2605RegRatedV = 0x16
|
||
|
drv2605RegClampV = 0x17
|
||
|
drv2605RegAutocalComp = 0x18
|
||
|
drv2605RegAutocalEmp = 0x19
|
||
|
drv2605RegFeedback = 0x1A
|
||
|
drv2605RegControl1 = 0x1B
|
||
|
drv2605RegControl2 = 0x1C
|
||
|
drv2605RegControl3 = 0x1D
|
||
|
drv2605RegControl4 = 0x1E
|
||
|
drv2605RegVBat = 0x21
|
||
|
drv2605RegLRAResoPeriod = 0x22
|
||
|
)
|
||
|
|
||
|
// DRV2605LDriver is the gobot driver for the TI/Adafruit DRV2605L Haptic Controller
|
||
|
// Device datasheet: http://www.ti.com/lit/ds/symlink/drv2605l.pdf
|
||
|
// Inspired by the Adafruit Python driver by Sean Mealin.
|
||
|
//
|
||
|
// Basic use:
|
||
|
//
|
||
|
// haptic := i2c.NewDRV2605Driver(adaptor)
|
||
|
// haptic.SetSequence([]byte{1, 13})
|
||
|
// haptic.Go()
|
||
|
//
|
||
|
type DRV2605LDriver struct {
|
||
|
name string
|
||
|
connection I2c
|
||
|
}
|
||
|
|
||
|
// NewDRV2605LDriver creates a new driver with the i2c interface for the DRV2605L device.
|
||
|
func NewDRV2605LDriver(c I2c) *DRV2605LDriver {
|
||
|
return &DRV2605LDriver{
|
||
|
name: "DRV2605L",
|
||
|
connection: c,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Name returns the name of the device.
|
||
|
func (d *DRV2605LDriver) Name() string {
|
||
|
return d.name
|
||
|
}
|
||
|
|
||
|
// SetName sets the name of the device.
|
||
|
func (d *DRV2605LDriver) SetName(name string) {
|
||
|
d.name = name
|
||
|
}
|
||
|
|
||
|
// Connection returns the connection of the device.
|
||
|
func (d *DRV2605LDriver) Connection() gobot.Connection {
|
||
|
return d.connection.(gobot.Connection)
|
||
|
}
|
||
|
|
||
|
// Start initializes the device.
|
||
|
func (d *DRV2605LDriver) Start() (err error) {
|
||
|
if err := d.initialize(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (d *DRV2605LDriver) readByteRegister(reg int) (val uint8, err error) {
|
||
|
var bytes []uint8
|
||
|
if bytes, err = d.connection.I2cRead(drv2605Address, reg); err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
return bytes[0], nil
|
||
|
}
|
||
|
|
||
|
func (d *DRV2605LDriver) writeByteRegister(reg uint8, val uint8) (err error) {
|
||
|
err = d.connection.I2cWrite(drv2605Address, []byte{reg, val})
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (d *DRV2605LDriver) writeByteRegisters(regValPairs [][2]uint8) (err error) {
|
||
|
for _, rv := range regValPairs {
|
||
|
reg, val := rv[0], rv[1]
|
||
|
if err = d.connection.I2cWrite(drv2605Address, []uint8{reg, val}); err != nil {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (d *DRV2605LDriver) initialize() (err error) {
|
||
|
if err = d.connection.I2cStart(drv2605Address); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
feedback, err := d.readByteRegister(drv2605RegFeedback)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
control, err := d.readByteRegister(drv2605RegControl3)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = d.writeByteRegisters([][2]uint8{
|
||
|
// leave standby, enter "internal trig" mode
|
||
|
{drv2605RegMode, 0},
|
||
|
// turn off real-time play
|
||
|
{drv2605RegRTPin, 0},
|
||
|
// init wave sequencer with "strong click"
|
||
|
{drv2605RegWaveSeq1, 1},
|
||
|
{drv2605RegWaveSeq1, 0},
|
||
|
// no physical parameter tweaks
|
||
|
{drv2605RegSustainPos, 0},
|
||
|
{drv2605RegSustainNeg, 0},
|
||
|
{drv2605RegBreak, 0},
|
||
|
// set up ERM open loop
|
||
|
{drv2605RegFeedback, feedback & 0x7f},
|
||
|
{drv2605RegControl3, control | 0x20},
|
||
|
})
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// SetMode sets the device in one of the eight modes as described in the
|
||
|
// datasheet. Defaults to mode 0, internal trig.
|
||
|
func (d *DRV2605LDriver) SetMode(newMode DRV2605Mode) (err error) {
|
||
|
mode, err := d.readByteRegister(drv2605RegMode)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// clear mode bits (lower three bits)
|
||
|
mode &= 0xf1
|
||
|
// set new mode bits
|
||
|
mode |= uint8(newMode)
|
||
|
|
||
|
err = d.writeByteRegister(drv2605RegMode, mode)
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// SetStandbyMode controls device low power mode
|
||
|
func (d *DRV2605LDriver) SetStandbyMode(standby bool) (err error) {
|
||
|
modeVal, err := d.readByteRegister(drv2605RegMode)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if standby {
|
||
|
modeVal |= drv2605Standby
|
||
|
} else {
|
||
|
modeVal &= 0xFF ^ drv2605Standby
|
||
|
}
|
||
|
|
||
|
err = d.writeByteRegister(drv2605RegMode, modeVal)
|
||
|
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// SelectLibrary selects which waveform library to play from, 1-7.
|
||
|
// See datasheet for more info.
|
||
|
func (d *DRV2605LDriver) SelectLibrary(library uint8) (err error) {
|
||
|
err = d.writeByteRegister(drv2605RegLibrary, library&0x7)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// GetPauseWaveform returns a special waveform ID used in SetSequence() to encode
|
||
|
// pauses between waveforms. Time is specified in tens of milliseconds
|
||
|
// ranging from 0ms (delayTime10MS = 0) to 1270ms (delayTime10MS = 127).
|
||
|
// Times out of range are clipped to fit.
|
||
|
func (d *DRV2605LDriver) GetPauseWaveform(delayTime10MS uint8) (pauseID uint8) {
|
||
|
if delayTime10MS > 127 {
|
||
|
delayTime10MS = 127
|
||
|
}
|
||
|
|
||
|
return delayTime10MS | 0x80
|
||
|
}
|
||
|
|
||
|
// SetSequence sets the sequence of waveforms to be played by the sequencer,
|
||
|
// specified by waveform id as described in the datasheet.
|
||
|
// The sequencer can play at most 8 waveforms in sequence, longer
|
||
|
// sequences will be truncated.
|
||
|
// A waveform id of zero marks the end of the sequence.
|
||
|
// Pauses can be encoded using GetPauseWaveform().
|
||
|
func (d *DRV2605LDriver) SetSequence(waveforms []uint8) (err error) {
|
||
|
if len(waveforms) < 8 {
|
||
|
waveforms = append(waveforms, 0)
|
||
|
}
|
||
|
if len(waveforms) > 8 {
|
||
|
waveforms = waveforms[0:8]
|
||
|
}
|
||
|
for i, w := range waveforms {
|
||
|
if err = d.writeByteRegister(uint8(drv2605RegWaveSeq1+i), w); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Go plays the current sequence of waveforms.
|
||
|
func (d *DRV2605LDriver) Go() (err error) {
|
||
|
err = d.writeByteRegister(drv2605RegGo, 1)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Halt halts the device.
|
||
|
func (d *DRV2605LDriver) Halt() (err error) {
|
||
|
// stop playback
|
||
|
if err = d.writeByteRegister(drv2605RegGo, 0); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// enter standby
|
||
|
return d.writeByteRegister(drv2605RegMode, 1)
|
||
|
}
|