/
drv2605l_driver.go
270 lines (233 loc) · 6.69 KB
/
drv2605l_driver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
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
connector Connector
connection Connection
Config
}
// NewDRV2605LDriver creates a new driver for the DRV2605L device.
//
// Params:
// conn 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 NewDRV2605LDriver(conn Connector, options ...func(Config)) *DRV2605LDriver {
driver := &DRV2605LDriver{
name: gobot.DefaultName("DRV2605L"),
connector: conn,
Config: NewConfig(),
}
for _, option := range options {
option(driver)
}
return driver
}
// 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.connector.(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) writeByteRegisters(regValPairs []struct{ reg, val uint8 }) (err error) {
for _, rv := range regValPairs {
if err = d.connection.WriteByteData(rv.reg, rv.val); err != nil {
break
}
}
return err
}
func (d *DRV2605LDriver) initialize() (err error) {
bus := d.GetBusOrDefault(d.connector.GetDefaultBus())
address := d.GetAddressOrDefault(drv2605Address)
d.connection, err = d.connector.GetConnection(address, bus)
if err != nil {
return
}
feedback, err := d.connection.ReadByteData(drv2605RegFeedback)
if err != nil {
return
}
control, err := d.connection.ReadByteData(drv2605RegControl3)
if err != nil {
return
}
err = d.writeByteRegisters([]struct{ reg, val 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
}
// 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.connection.ReadByteData(drv2605RegMode)
if err != nil {
return err
}
// clear mode bits (lower three bits)
mode &= 0xf8
// set new mode bits
mode |= uint8(newMode)
err = d.connection.WriteByteData(drv2605RegMode, mode)
return err
}
// SetStandbyMode controls device low power mode
func (d *DRV2605LDriver) SetStandbyMode(standby bool) (err error) {
modeVal, err := d.connection.ReadByteData(drv2605RegMode)
if err != nil {
return err
}
if standby {
modeVal |= drv2605Standby
} else {
modeVal &= 0xFF ^ drv2605Standby
}
err = d.connection.WriteByteData(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.connection.WriteByteData(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.connection.WriteByteData(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.connection.WriteByteData(drv2605RegGo, 1)
return err
}
// Halt halts the device.
func (d *DRV2605LDriver) Halt() (err error) {
if d.connection != nil {
// stop playback
if err = d.connection.WriteByteData(drv2605RegGo, 0); err != nil {
return err
}
// enter standby
return d.SetStandbyMode(true)
}
return
}