SensorLib 0.5.0
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
HapticDriver_DRV2605.cpp
Go to the documentation of this file.
1
29#include "../SensorBuildOpt.h"
30#if !SENSORLIB_EXCLUDE_HAPTIC_DRV2605
31
34
35using namespace DRV2605Regs;
36
38 : HapticBase("DRV2605")
39 , _currentLibrary(1)
40 , _waveformCount(0)
41 , _isERM(true)
42 , _isStandby(false)
43{
44 for (int i = 0; i < 8; i++) {
45 _waveformSeq[i] = 0;
46 }
47}
48
53
55{
56 stop();
57 setReady(false);
58}
59
61{
62 return _isReady;
63}
64
66{
67 return "DRV2605";
68}
69
71{
72 if (_isStandby) {
73 // Standby can't run
74 return false;
75 }
76 return writeReg(DRV2605_REG_GO, 1) == 0;
77}
78
80{
81 return writeReg(DRV2605_REG_GO, 0) == 0;
82}
83
85{
86 int value = readReg(DRV2605_REG_GO);
87 return value > 0 && value != -1;
88}
89
91{
92 if (_isStandby) return HapticStatus::STANDBY;
93 if (!_isReady) return HapticStatus::ERROR;
94 if (isPlaying()) return HapticStatus::PLAYING;
95 return HapticStatus::IDLE;
96}
97
102
104{
105 // DRV2605 doesn't have a dedicated gain register
106 // For ROM library effects, the intensity is pre-defined
107 // We can only use RTP mode for direct amplitude control
108 // Store the value for reference, but return false to indicate
109 // this chip doesn't support runtime gain adjustment
110 (void)gain;
111 return false;
112}
113
115{
116 // DRV2605 doesn't have a gain register for ROM effects
117 // Return stored value or 0 to indicate not applicable
118 return 0;
119}
120
122{
123 if (!_isReady) return false;
124 if (_isStandby)return false;
125 setWaveform(0, static_cast<uint8_t>(effect));
126 setWaveform(1, 0);
127 return run();
128}
129
131{
132 return playEffect(effect);
133}
134
135void HapticDriver_DRV2605::continuousVibration(uint32_t duration_ms, bool blocking)
136{
137 (void)duration_ms;
138 (void)blocking;
139}
140
144
146{
147 if (slot >= 8) return false;
148 _waveformSeq[slot] = static_cast<uint8_t>(effect);
149 setWaveform(slot, _waveformSeq[slot]);
150 return true;
151}
152
154{
155 for (uint8_t i = 0; i < 8; i++) {
156 _waveformSeq[i] = 0;
157 setWaveform(i, 0);
158 }
159 return true;
160}
161
163{
164 return run();
165}
166
168{
170 cap.hasF0Calibration = 0;
171 cap.hasVbatCompensation = 0;
172 cap.hasRTP = 1;
173 cap.hasSequence = 1;
174 cap.hasAutoCalibration = 1;
175 cap.hasBreakEffect = 1;
176 cap.hasOverdrive = 1;
177 cap.hasContinuousMode = 0;
178 cap.maxEffectCount = 117; // ROM library has many effects
179 cap.maxSequenceLength = 8;
180 cap.maxDurationMs = 0; // Duration depends on waveform, not continuous
181 return cap;
182}
183
185{
186 int chipID = readReg(DRV2605_REG_STATUS);
187 if (chipID < 0) return 0;
188 return static_cast<uint8_t>(chipID >> 5);
189}
190
195
197{
198 _isERM = (type == HapticActuatorType::ERM);
199
200 if (_isERM) {
201 writeReg(DRV2605_REG_LIBRARY, 1);
202 updateBits(DRV2605_REG_FEEDBACK, 0x80, 0x00);
203 } else {
204 writeReg(DRV2605_REG_LIBRARY, 6);
205 updateBits(DRV2605_REG_FEEDBACK, 0x80, 0x80);
206 }
207 return true;
208}
209
211{
212 uint8_t value = 0;
213 switch (mode) {
215 value = 0x00;
216 break;
218 value = 0x01;
219 break;
221 value = 0x02;
222 break;
224 value = 0x03;
225 break;
227 value = 0x04;
228 break;
230 value = 0x05;
231 break;
233 value = 0x06;
234 break;
236 value = 0x07;
237 break;
239 value = 0x40;
240 break;
241 default:
242 return false;
243 }
244 if (writeReg(DRV2605_REG_MODE, value) == 0) {
245 _isStandby = (mode == HapticMode::STANDBY);
246 return true;
247 }
248 return false;
249}
250
252{
253 if (_isStandby) {
254 return HapticMode::STANDBY;
255 }
256 int value = readReg(DRV2605_REG_MODE);
257 if (value < 0) {
259 }
260 return static_cast<HapticMode>(value & 0x07);
261}
262
264{
265 return writeReg(DRV2605_REG_RTPIN, value) == 0;
266}
267
269{
270 int value = readReg(DRV2605_REG_RTPIN);
271 return value >= 0 ? static_cast<uint8_t>(value) : 0;
272}
273
275{
276 int result = autoCal();
277 return result >= 0;
278}
279
281{
282 return true; // DRV2605 typically needs calibration
283}
284
286{
287 int value = readReg(DRV2605_REG_LRARESON);
288 if (value < 0) return 0;
289
290 uint8_t period = static_cast<uint8_t>(value & 0x7F);
291 if (period == 0) return 0;
292
293 return static_cast<uint32_t>(1000000 / (period * 75));
294}
295
297{
298 int vbat = readReg(DRV2605_REG_VBAT);
299 if (vbat < 0) {
300 return 0;
301 }
302 uint32_t mv = (static_cast<float>(vbat) * 5.6 / 255) * 1000;
303 return mv;
304}
305
306void HapticDriver_DRV2605::setWaveform(uint8_t slot, uint8_t w)
307{
308 writeReg(static_cast<uint8_t>(DRV2605_REG_WAVESEQ1 + slot), w);
309}
310
312{
313 _currentLibrary = lib;
314 writeReg(DRV2605_REG_LIBRARY, lib);
315}
316
318{
319 int value = readReg(DRV2605_REG_GO);
320 return value == 0;
321}
322
324{
325 run();
326}
327
329{
330 writeReg(DRV2605_REG_RATEDV, value);
331}
332
334{
335 writeReg(DRV2605_REG_CLAMPV, value);
336}
337
339{
341 run();
342
343 uint32_t start = hal->millis();
344 while (!isDone() && (hal->millis() - start < 1000)) {
345 hal->delay(10);
346 }
347
348 if (isDone()) {
349 int comp = readReg(DRV2605_REG_AUTOCALCOMP);
350 int backEmf = readReg(DRV2605_REG_AUTOCALEMP);
351
353
354 if (comp >= 0 && backEmf >= 0) {
355 return comp;
356 }
357 }
358
359 return -1;
360}
361
363{
364 int value = readReg(DRV2605_REG_CONTROL2);
365 if (value >= 0) {
366 if (enable) {
367 value |= 0x10;
368 } else {
369 value &= ~0x10;
370 }
371 writeReg(DRV2605_REG_CONTROL2, static_cast<uint8_t>(value));
372 }
373}
374
376{
377 writeReg(DRV2605_REG_OVERDRIVE, cycles);
378}
379
381{
382 writeReg(DRV2605_REG_BREAK, time);
383}
384
386{
387 int value = readReg(DRV2605_REG_CONTROL3);
388 if (value >= 0) {
389 if (enable) {
390 value |= 0x80;
391 } else {
392 value &= ~0x80;
393 }
394 writeReg(DRV2605_REG_CONTROL3, static_cast<uint8_t>(value));
395 }
396}
397
403
405{
406 writeReg(DRV2605_REG_CONTROL4, value);
407}
408
410{
411 int value = readReg(DRV2605_REG_LRARESON);
412 return value >= 0 ? static_cast<uint8_t>(value & 0x7F) : 0;
413}
414
415bool HapticDriver_DRV2605::initImpl(uint8_t param)
416{
417 (void)param;
418
419 int chipID = readReg(DRV2605_REG_STATUS);
420 if (chipID < 0) {
421 return false;
422 }
423
424 chipID >>= 5;
425
426 switch (chipID) {
427 case DRV2604_CHIP_ID:
428 case DRV2605_CHIP_ID:
429 case DRV2604L_CHIP_ID:
430 case DRV2605L_CHIP_ID:
431 case DRV2605X_CHIP_ID:
432 break;
433 default:
434 return false;
435 }
436
437 writeReg(DRV2605_REG_MODE, 0x00);
438 writeReg(DRV2605_REG_RTPIN, 0x00);
439
440 writeReg(DRV2605_REG_WAVESEQ1, 1);
441 writeReg(DRV2605_REG_WAVESEQ2, 0);
442
443 writeReg(DRV2605_REG_OVERDRIVE, 0);
444 writeReg(DRV2605_REG_SUSTAINPOS, 0);
445 writeReg(DRV2605_REG_SUSTAINNEG, 0);
446 writeReg(DRV2605_REG_BREAK, 0);
447 writeReg(DRV2605_REG_AUDIOMAX, 0x64);
448
449 int value = readReg(DRV2605_REG_FEEDBACK);
450 if (value == -1) {
451 return false;
452 }
453 writeReg(DRV2605_REG_FEEDBACK, static_cast<uint8_t>(value & 0x7F));
454
455 int control3 = readReg(DRV2605_REG_CONTROL3);
456 if (control3 == -1) {
457 return false;
458 }
459 writeReg(DRV2605_REG_CONTROL3, static_cast<uint8_t>(control3 | 0x20));
460
461 return true;
462}
463
464#endif
HapticStatus
Vibration playback status.
@ PLAYING
Currently playing.
@ IDLE
Not playing.
@ ERROR
Error state.
@ STANDBY
Standby mode.
HapticActuatorType
Actuator type.
@ LRA
Linear Resonant Actuator.
@ ERM
Eccentric Rotating Mass motor.
HapticMode
Generic haptic operating mode.
@ INTERNAL_TRIGGER
Play by selecting waveforms/effects and calling run()
@ EXT_TRIGGER_LEVEL
External trigger on level (pin state)
@ AUTO_CALIBRATE
Auto-calibration mode.
@ DIAGNOSTICS
Diagnostics mode.
@ PWM_ANALOG
PWM or analog input drive.
@ AUDIO_TO_VIBE
Audio input to vibration.
@ STANDBY
Standby mode.
@ EXT_TRIGGER_EDGE
External trigger on edge (pin interrupt)
@ REAL_TIME_PLAYBACK
RTP mode (direct drive value)
uint16_t HapticEffectId
Haptic effect ID type.
@license MIT License
@license MIT License
std::unique_ptr< SensorHal > hal
Abstract base class for haptic drivers.
void setReady(bool ready)
Set ready state.
bool isDone() const
Check if playback is done.
uint32_t getVbat() override
Get the battery voltage.
void setAutoBrake(bool enable)
Enable/disable automatic braking.
void setRtpOverdrive(bool enable)
Enable/disable RTP overdrive.
bool setActuatorType(HapticActuatorType type) override
Set the actuator type.
HapticActuatorType getActuatorType() const override
Get the actuator type.
bool calibrate() override
Perform auto-calibration.
uint32_t getF0() const override
Get the measured resonant frequency (F0).
void setCtrl4(uint8_t value)
Set the control4 register value.
bool run() override
Start haptic playback.
~HapticDriver_DRV2605() override
Destructor.
void setRatedVoltage(uint8_t value)
Set the rated voltage for auto-calibration.
bool isReady() const override
Check if the driver is initialized and ready.
bool playEffectAsync(HapticEffectId effect) override
Play a haptic effect (non-blocking).
void selectLibrary(uint8_t lib)
Select the ROM waveform library.
void setBrakeTime(uint8_t time)
Set the brake time offset.
bool isPlaying() const override
Check if haptic is currently playing.
void end() override
Deinitialize the driver and release resources.
void continuousVibration(uint32_t duration_ms, bool blocking=true) override
Play a continuous vibration for specified duration.
void emergencyStop() override
Emergency stop - stops all vibration immediately.
int autoCal()
Perform auto-calibration and return compensation result.
void setOverdriveClamp(uint8_t value)
Set the overdrive clamp voltage for auto-calibration.
void setOverdriveTime(uint8_t cycles)
Set the number of overdrive cycles.
uint8_t getRealtimeValue() const
Get the current RTP value.
bool setMode(HapticMode mode) override
Set the operating mode.
void vibrationUpdate() override
Update vibration state (for non-blocking mode).
bool setSequence(uint8_t slot, HapticEffectId effect) override
Set a waveform in the sequence.
HapticStatus getStatus() const override
Get current playback status.
uint8_t getChipID() const override
Get the chip ID.
bool setGain(uint8_t gain) override
Set the gain/amplitude.
bool playSequence() override
Play the waveform sequence.
uint8_t getGain() const override
Get the current gain value.
void setERMLRA(bool erm)
Enable/disable ERM/LRA mode.
bool playEffect(HapticEffectId effect) override
Play a haptic effect.
const char * getChipName() const override
Get the chip name.
HapticMode getMode() const override
Get the current operating mode.
bool stop() override
Stop haptic playback immediately.
bool clearSequence() override
Clear the waveform sequence.
HapticDriver_DRV2605()
Construct an uninitialized driver instance.
void trigger()
Trigger a single playback cycle.
HapticCapabilities getCapabilities() const override
Get device capabilities.
bool setRealtimeValue(uint8_t value) override
Set RTP (real-time playback) value.
uint8_t getLRAFrequency() const
Read the LRA resonance period (for LRA calibration).
bool needsCalibration() const override
Check if calibration is needed.
void setWaveform(uint8_t slot, uint8_t w)
Set a waveform entry in the playback sequence table.
int readReg(uint8_t reg) const
int writeReg(uint8_t reg, uint8_t val)
int updateBits(uint8_t reg, uint8_t mask, uint8_t value_shifted)
uint8_t i
Device capability flags.
uint8_t maxSequenceLength
Maximum waveform sequence length.
uint8_t hasF0Calibration
Supports F0 (resonant frequency) calibration.
uint16_t maxDurationMs
Maximum vibration duration in ms (0 = unlimited)
uint8_t hasAutoCalibration
Supports auto-calibration.
uint8_t hasVbatCompensation
Supports automatic voltage compensation.
uint8_t hasRTP
Supports Real-Time Playback mode.
uint8_t hasBreakEffect
Supports brake/break effects.
uint8_t hasOverdrive
Supports overdrive effects.
uint8_t maxEffectCount
Maximum number of effect IDs supported.
uint8_t hasContinuousMode
Supports continuous vibration mode.
uint8_t hasSequence
Supports waveform sequencing.