Fix for hack that worked around iOS app
Diff: Haptics.cpp
- Revision:
- 0:8c0ecbdd3449
- Child:
- 2:4f76784f8968
diff -r 000000000000 -r 8c0ecbdd3449 Haptics.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Haptics.cpp Tue Feb 02 22:00:49 2016 +0000 @@ -0,0 +1,232 @@ +/****************************************************************************** + * Haptics.c + * + * Created on: Dec 16, 2011 + * Board: DRV2603EVM-CT RevD + * Author: a0866685 + * + * Description: This file contains the functions for sending haptics waveforms. + * Edit this file when changing actuators. + * + * @TODO - Update this file when changing between actuators types + * (ERM, LRA, Piezo) + * + ******************************************************************************/ +#include "Haptics.h" +#include "Actuator_Waveforms.h" + +// private variables +//static uint8_t j,k; + +// public variables +uint16_t Haptics_dumbModeTick = DUMBTICK; // Sets the LRA Auto-resonance off frequency (use DUMBTICK above to set frequency) +uint16_t Haptics_resonantModeTick; + +DigitalOut LRA_EN(P0_12); +PwmOut LRA(P0_11); + +extern DigitalOut led1; + +Ticker hapticsTicker; +volatile uint16_t lraPlaybackMode = 0; +volatile int lraCurrent = 0; +volatile int lraTarget = 0; +volatile uint16_t lraDelay = 0; +volatile uint16_t placeInWaveform = 0; +volatile uint16_t waveformDelayCounter = 0; +const Waveform* volatile waveform; +const Waveform* volatile heartbeatWaveform = &lra_tick; + + +// TODO: Support haptics modalities here: off, waveform, delayed waveform, ramp to target + +// Called every 5ms to update LRA amplitude based on desired haptics response +void hapticsCallback() { + switch (lraPlaybackMode) { + case LRA_MODE_WAVEFORM: + // play the current amplitude + //led1 = 1; + + if(waveform->data[placeInWaveform] == 0x80) { + LRA.pulsewidth_us(0); + LRA_EN = 0; + } else { + LRA_EN = 1; + //LRA.pulsewidth_us(90); + LRA.pulsewidth_us(((((uint16_t)waveform->data[placeInWaveform])*3) >> 3)); // mult by 3 shift right by 4 to get in range of 0..47 + + } + + // run down the timer on this amplitude + waveformDelayCounter++; + if (waveformDelayCounter >= waveform->data[placeInWaveform+1]) { + // move to the next waveform entry and reset the timer when necessary + waveformDelayCounter=0; + placeInWaveform += 2; + if (placeInWaveform >= waveform->length) { + //led1 = 0; + LRA.pulsewidth_us(0); + LRA_EN = 0; + placeInWaveform = 0; + waveformDelayCounter = 0; + lraPlaybackMode = LRA_MODE_OFF; + } + } + break; + case LRA_MODE_DELAYED_WAVEFORM: + waveformDelayCounter+=5; // every tick is 5ms + if (waveformDelayCounter >= lraDelay) { + waveformDelayCounter = 0; + lraPlaybackMode = LRA_MODE_WAVEFORM; + } + break; + case LRA_MODE_RAMP_TO_TARGET: + // full ramp from 384 to 768 (threshold to full) takes 384*5 = 1920ms with step size = 1 + if (lraTarget > lraCurrent) { + lraCurrent += 2; + } else { + lraCurrent -= 2; + } + LRA_EN = 1; + //led1 = 1; + LRA.pulsewidth_us((lraCurrent) >> 3); //divide by 8 to get in range of 0..95 + break; + case LRA_MODE_OFF: + default: + // Do nothing + break; + } +} + +/** + * Haptics_Init - initialize haptics variables and settings + */ +void Haptics_Init(void) +{ + // mbed uses 4uS timer precision, so keep this as large as possible for better granularity + // 96 uS period means 96 is the maximum pulse width. So we need to scale from 256 to 96, or mult by 3, and shift right by 3. + LRA.period_us(96); // 96 uS -> 10.4 Khz (needs to be between 10Khz and 250Khz) + + hapticsTicker.attach(&hapticsCallback, 0.005); // update haptics every 5 ms + + Haptics_resonantModeTick = (unsigned int) Haptics_dumbModeTick * 2; +} + + +/* + * Haptics_OutputWaveform - control the PWM output pattern + * @param struct Waveform - the waveform output type, length in bytes, and data + */ +void Haptics_OutputWaveform(const Waveform* newWaveform) +{ + + if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) { + waveform = newWaveform; + lraPlaybackMode = LRA_MODE_WAVEFORM; + } else { + //printf("OutputWaveform: mode=%d, delay=%d, place=%d\n\r", lraPlaybackMode, waveformDelayCounter, placeInWaveform); + } +} + +// Override any currently active haptic effect +void Haptics_OverrideOutputWaveform(const Waveform* newWaveform) +{ + //led1 = !led1; + placeInWaveform = 0; + waveform = newWaveform; + LRA_EN = 1; + LRA.pulsewidth_us((((int)waveform->data[placeInWaveform])*3) >> 3); // mult by 3 shift right by 2 to get in range of 0..95 + lraPlaybackMode = LRA_MODE_WAVEFORM; +} + +void Haptics_OutputDelayedHeartbeat(uint16_t delay) { + Haptics_OutputDelayedWaveform(heartbeatWaveform, delay); +} + +void Haptics_SetHeartbeatWaveform (int waveformNum) { + printf("SetHeartbeatWaveform to %d.\n\r", waveformNum); + + switch (waveformNum) { + case 1: + heartbeatWaveform = &lra_click_nobrake; + break; + case 2: + heartbeatWaveform = &lra_alert; + break; + case 3: + heartbeatWaveform = &lra_rampup; + break; + case 4: + heartbeatWaveform = &lra_rampdown; + break; + case 5: + heartbeatWaveform = &lra_softclick; + break; + case 6: + heartbeatWaveform = &lra_softbump; + break; + case 7: + heartbeatWaveform = &lra_softalert; + break; + case 8: + heartbeatWaveform = &lra_rampupdoubleclick; + break; + case 0: + default: + heartbeatWaveform = &lra_tick; + } +} + +void Haptics_OutputDelayedWaveform(const Waveform* newWaveform, uint16_t delay) { + + if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) { + placeInWaveform = 0; + waveformDelayCounter = 0; + lraDelay = delay; + waveform = newWaveform; + lraPlaybackMode = LRA_MODE_DELAYED_WAVEFORM; + } else { + //printf("Haptics: mode=%d, delay=%d, until=%d, place=%d\n\r", lraPlaybackMode, waveformDelayCounter, lraDelay, placeInWaveform); + } +} + +// Ignored while waveform is playing or queued. Overridden by waveforms. +void Haptics_SetRampTarget(float amplitude) +{ + if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) { + if (lraPlaybackMode == LRA_MODE_OFF) { + lraCurrent = 384; // reset to threshold off if this is the first ramp target + } + if (amplitude > 1.0) amplitude = 1.0; + if (amplitude < 0.0) amplitude = 0.0; + lraTarget = (int) (amplitude*768); // (96 * 8) + lraPlaybackMode = LRA_MODE_RAMP_TO_TARGET; + //printf("Ramp current=%d, target=%d\n\r", lraCurrent>>3, lraTarget>>3); + } +} + +// Buzz this many times +void Haptics_OutputCount (uint16_t count) { + switch (count) { + case 1: + Haptics_OutputWaveform(&lra_click_nobrake); + break; + case 2: + Haptics_OutputWaveform(&lra_doubleclick_nobrake); + break; + case 3: + Haptics_OutputWaveform(&lra_tripleclick_nobrake); + break; + } +} + +// Stop haptics regardless of mode +void Haptics_Off() +{ + lraPlaybackMode = LRA_MODE_OFF; +} + +bool isHapticsOff() +{ + return (lraPlaybackMode == LRA_MODE_OFF); +}