Fix for hack that worked around iOS app
Haptics.cpp
- Committer:
- roysandberg
- Date:
- 2016-03-03
- Revision:
- 3:b64f3abb3c0b
- Parent:
- 2:4f76784f8968
- Child:
- 4:d3858592d3b5
File content as of revision 3:b64f3abb3c0b:
/****************************************************************************** * 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 "Actuator_Waveforms.h" // private variables //static uint8_t j,k; extern float lraEffectMultiplier; // defined in main.cpp // 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; // Used for off-mode haptics and LED signature Timeout firstLEDOff; Timeout secondBuzz; Timeout secondLEDOff; 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; const Waveform* volatile heartbeatWaveform = &lra_rampdown; // 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; float scaledWaveform = ((float)waveform->data[placeInWaveform]) * 0.375 * lraEffectMultiplier; // 0.375 is 96/256 LRA.pulsewidth_us((uint16_t)scaledWaveform); //LRA.pulsewidth_us(((((uint16_t)waveform->data[placeInWaveform])*3) >> 3)); // mult by 3 shift right by 3 to get in range of 0..96 //LRA.pulsewidth_us(90); // used for fixed intensity output (for testing) } // 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 LRA.pulsewidth_us(0); LRA_EN = 0; placeInWaveform = 0; waveformDelayCounter = 0; 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); } } void LEDOffCallback() { led1=0; } void BuzzCallback() { Haptics_OutputWaveform(&lra_alert); led1 = 1; } // generate off mode haptic response // This is 2 buzzes separated by 300 ms, and 2 led blinks with the same timing. void LeavingOffModeHapticResponse(int ledFinalState) { // Turn on LED and generate first buzz BuzzCallback(); // Setup callback to turn off LED after 50ms firstLEDOff.attach(&LEDOffCallback,0.05); // Setup callback to generate second buzz after 300ms, and turn on LED second time secondBuzz.attach(&BuzzCallback,0.3); // Setup callback to turn off LED after 350mS if (ledFinalState == 0) { secondLEDOff.attach(&LEDOffCallback,0.35); } } void EnteringOffModeHapticResponse() { Haptics_OutputWaveform(&lra_rampdown); led1 = 0; } // 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); }