Fix for hack that worked around iOS app

Committer:
roysandberg
Date:
Thu Feb 25 00:19:46 2016 +0000
Revision:
2:4f76784f8968
Parent:
0:8c0ecbdd3449
Child:
3:b64f3abb3c0b
On/Off/Twilight Mode

Who changed what in which revision?

UserRevisionLine numberNew contents of line
roysandberg 0:8c0ecbdd3449 1 /******************************************************************************
roysandberg 0:8c0ecbdd3449 2 * Haptics.c
roysandberg 0:8c0ecbdd3449 3 *
roysandberg 0:8c0ecbdd3449 4 * Created on: Dec 16, 2011
roysandberg 0:8c0ecbdd3449 5 * Board: DRV2603EVM-CT RevD
roysandberg 0:8c0ecbdd3449 6 * Author: a0866685
roysandberg 0:8c0ecbdd3449 7 *
roysandberg 0:8c0ecbdd3449 8 * Description: This file contains the functions for sending haptics waveforms.
roysandberg 0:8c0ecbdd3449 9 * Edit this file when changing actuators.
roysandberg 0:8c0ecbdd3449 10 *
roysandberg 0:8c0ecbdd3449 11 * @TODO - Update this file when changing between actuators types
roysandberg 0:8c0ecbdd3449 12 * (ERM, LRA, Piezo)
roysandberg 0:8c0ecbdd3449 13 *
roysandberg 0:8c0ecbdd3449 14 ******************************************************************************/
roysandberg 2:4f76784f8968 15
roysandberg 0:8c0ecbdd3449 16 #include "Actuator_Waveforms.h"
roysandberg 0:8c0ecbdd3449 17
roysandberg 0:8c0ecbdd3449 18 // private variables
roysandberg 0:8c0ecbdd3449 19 //static uint8_t j,k;
roysandberg 0:8c0ecbdd3449 20
roysandberg 2:4f76784f8968 21 extern float lraEffectMultiplier; // defined in main.cpp
roysandberg 2:4f76784f8968 22
roysandberg 0:8c0ecbdd3449 23 // public variables
roysandberg 0:8c0ecbdd3449 24 uint16_t Haptics_dumbModeTick = DUMBTICK; // Sets the LRA Auto-resonance off frequency (use DUMBTICK above to set frequency)
roysandberg 0:8c0ecbdd3449 25 uint16_t Haptics_resonantModeTick;
roysandberg 0:8c0ecbdd3449 26
roysandberg 0:8c0ecbdd3449 27 DigitalOut LRA_EN(P0_12);
roysandberg 0:8c0ecbdd3449 28 PwmOut LRA(P0_11);
roysandberg 0:8c0ecbdd3449 29
roysandberg 0:8c0ecbdd3449 30 extern DigitalOut led1;
roysandberg 0:8c0ecbdd3449 31
roysandberg 2:4f76784f8968 32
roysandberg 2:4f76784f8968 33 // Used for off-mode haptics and LED signature
roysandberg 2:4f76784f8968 34 Timeout firstLEDOff;
roysandberg 2:4f76784f8968 35 Timeout secondBuzz;
roysandberg 2:4f76784f8968 36 Timeout secondLEDOff;
roysandberg 2:4f76784f8968 37
roysandberg 0:8c0ecbdd3449 38 Ticker hapticsTicker;
roysandberg 0:8c0ecbdd3449 39 volatile uint16_t lraPlaybackMode = 0;
roysandberg 0:8c0ecbdd3449 40 volatile int lraCurrent = 0;
roysandberg 0:8c0ecbdd3449 41 volatile int lraTarget = 0;
roysandberg 0:8c0ecbdd3449 42 volatile uint16_t lraDelay = 0;
roysandberg 0:8c0ecbdd3449 43 volatile uint16_t placeInWaveform = 0;
roysandberg 0:8c0ecbdd3449 44 volatile uint16_t waveformDelayCounter = 0;
roysandberg 0:8c0ecbdd3449 45 const Waveform* volatile waveform;
roysandberg 2:4f76784f8968 46 //const Waveform* volatile heartbeatWaveform = &lra_tick;
roysandberg 2:4f76784f8968 47 const Waveform* volatile heartbeatWaveform = &lra_rampdown;
roysandberg 2:4f76784f8968 48
roysandberg 2:4f76784f8968 49
roysandberg 0:8c0ecbdd3449 50
roysandberg 0:8c0ecbdd3449 51
roysandberg 0:8c0ecbdd3449 52 // TODO: Support haptics modalities here: off, waveform, delayed waveform, ramp to target
roysandberg 0:8c0ecbdd3449 53
roysandberg 0:8c0ecbdd3449 54 // Called every 5ms to update LRA amplitude based on desired haptics response
roysandberg 0:8c0ecbdd3449 55 void hapticsCallback() {
roysandberg 0:8c0ecbdd3449 56 switch (lraPlaybackMode) {
roysandberg 0:8c0ecbdd3449 57 case LRA_MODE_WAVEFORM:
roysandberg 0:8c0ecbdd3449 58 // play the current amplitude
roysandberg 0:8c0ecbdd3449 59 //led1 = 1;
roysandberg 0:8c0ecbdd3449 60
roysandberg 0:8c0ecbdd3449 61 if(waveform->data[placeInWaveform] == 0x80) {
roysandberg 0:8c0ecbdd3449 62 LRA.pulsewidth_us(0);
roysandberg 0:8c0ecbdd3449 63 LRA_EN = 0;
roysandberg 0:8c0ecbdd3449 64 } else {
roysandberg 0:8c0ecbdd3449 65 LRA_EN = 1;
roysandberg 2:4f76784f8968 66 float scaledWaveform = ((float)waveform->data[placeInWaveform]) * 0.375 * lraEffectMultiplier; // 0.375 is 96/256
roysandberg 2:4f76784f8968 67 LRA.pulsewidth_us((uint16_t)scaledWaveform);
roysandberg 2:4f76784f8968 68 //LRA.pulsewidth_us(((((uint16_t)waveform->data[placeInWaveform])*3) >> 3)); // mult by 3 shift right by 3 to get in range of 0..96
roysandberg 2:4f76784f8968 69 //LRA.pulsewidth_us(90); // used for fixed intensity output (for testing)
roysandberg 0:8c0ecbdd3449 70 }
roysandberg 0:8c0ecbdd3449 71
roysandberg 0:8c0ecbdd3449 72 // run down the timer on this amplitude
roysandberg 0:8c0ecbdd3449 73 waveformDelayCounter++;
roysandberg 0:8c0ecbdd3449 74 if (waveformDelayCounter >= waveform->data[placeInWaveform+1]) {
roysandberg 0:8c0ecbdd3449 75 // move to the next waveform entry and reset the timer when necessary
roysandberg 0:8c0ecbdd3449 76 waveformDelayCounter=0;
roysandberg 0:8c0ecbdd3449 77 placeInWaveform += 2;
roysandberg 0:8c0ecbdd3449 78 if (placeInWaveform >= waveform->length) {
roysandberg 0:8c0ecbdd3449 79 //led1 = 0;
roysandberg 0:8c0ecbdd3449 80 LRA.pulsewidth_us(0);
roysandberg 0:8c0ecbdd3449 81 LRA_EN = 0;
roysandberg 0:8c0ecbdd3449 82 placeInWaveform = 0;
roysandberg 0:8c0ecbdd3449 83 waveformDelayCounter = 0;
roysandberg 0:8c0ecbdd3449 84 lraPlaybackMode = LRA_MODE_OFF;
roysandberg 0:8c0ecbdd3449 85 }
roysandberg 0:8c0ecbdd3449 86 }
roysandberg 0:8c0ecbdd3449 87 break;
roysandberg 0:8c0ecbdd3449 88 case LRA_MODE_DELAYED_WAVEFORM:
roysandberg 0:8c0ecbdd3449 89 waveformDelayCounter+=5; // every tick is 5ms
roysandberg 0:8c0ecbdd3449 90 if (waveformDelayCounter >= lraDelay) {
roysandberg 0:8c0ecbdd3449 91 waveformDelayCounter = 0;
roysandberg 0:8c0ecbdd3449 92 lraPlaybackMode = LRA_MODE_WAVEFORM;
roysandberg 0:8c0ecbdd3449 93 }
roysandberg 0:8c0ecbdd3449 94 break;
roysandberg 0:8c0ecbdd3449 95 case LRA_MODE_RAMP_TO_TARGET:
roysandberg 0:8c0ecbdd3449 96 // full ramp from 384 to 768 (threshold to full) takes 384*5 = 1920ms with step size = 1
roysandberg 0:8c0ecbdd3449 97 if (lraTarget > lraCurrent) {
roysandberg 0:8c0ecbdd3449 98 lraCurrent += 2;
roysandberg 0:8c0ecbdd3449 99 } else {
roysandberg 0:8c0ecbdd3449 100 lraCurrent -= 2;
roysandberg 0:8c0ecbdd3449 101 }
roysandberg 0:8c0ecbdd3449 102 LRA_EN = 1;
roysandberg 0:8c0ecbdd3449 103 //led1 = 1;
roysandberg 0:8c0ecbdd3449 104 LRA.pulsewidth_us((lraCurrent) >> 3); //divide by 8 to get in range of 0..95
roysandberg 0:8c0ecbdd3449 105 break;
roysandberg 0:8c0ecbdd3449 106 case LRA_MODE_OFF:
roysandberg 0:8c0ecbdd3449 107 default:
roysandberg 0:8c0ecbdd3449 108 // Do nothing
roysandberg 0:8c0ecbdd3449 109 break;
roysandberg 0:8c0ecbdd3449 110 }
roysandberg 0:8c0ecbdd3449 111 }
roysandberg 0:8c0ecbdd3449 112
roysandberg 0:8c0ecbdd3449 113 /**
roysandberg 0:8c0ecbdd3449 114 * Haptics_Init - initialize haptics variables and settings
roysandberg 0:8c0ecbdd3449 115 */
roysandberg 0:8c0ecbdd3449 116 void Haptics_Init(void)
roysandberg 0:8c0ecbdd3449 117 {
roysandberg 0:8c0ecbdd3449 118 // mbed uses 4uS timer precision, so keep this as large as possible for better granularity
roysandberg 0:8c0ecbdd3449 119 // 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.
roysandberg 0:8c0ecbdd3449 120 LRA.period_us(96); // 96 uS -> 10.4 Khz (needs to be between 10Khz and 250Khz)
roysandberg 0:8c0ecbdd3449 121
roysandberg 0:8c0ecbdd3449 122 hapticsTicker.attach(&hapticsCallback, 0.005); // update haptics every 5 ms
roysandberg 0:8c0ecbdd3449 123
roysandberg 0:8c0ecbdd3449 124 Haptics_resonantModeTick = (unsigned int) Haptics_dumbModeTick * 2;
roysandberg 0:8c0ecbdd3449 125 }
roysandberg 0:8c0ecbdd3449 126
roysandberg 0:8c0ecbdd3449 127
roysandberg 0:8c0ecbdd3449 128 /*
roysandberg 0:8c0ecbdd3449 129 * Haptics_OutputWaveform - control the PWM output pattern
roysandberg 0:8c0ecbdd3449 130 * @param struct Waveform - the waveform output type, length in bytes, and data
roysandberg 0:8c0ecbdd3449 131 */
roysandberg 0:8c0ecbdd3449 132 void Haptics_OutputWaveform(const Waveform* newWaveform)
roysandberg 0:8c0ecbdd3449 133 {
roysandberg 0:8c0ecbdd3449 134
roysandberg 0:8c0ecbdd3449 135 if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) {
roysandberg 0:8c0ecbdd3449 136 waveform = newWaveform;
roysandberg 0:8c0ecbdd3449 137 lraPlaybackMode = LRA_MODE_WAVEFORM;
roysandberg 0:8c0ecbdd3449 138 } else {
roysandberg 0:8c0ecbdd3449 139 //printf("OutputWaveform: mode=%d, delay=%d, place=%d\n\r", lraPlaybackMode, waveformDelayCounter, placeInWaveform);
roysandberg 0:8c0ecbdd3449 140 }
roysandberg 0:8c0ecbdd3449 141 }
roysandberg 0:8c0ecbdd3449 142
roysandberg 0:8c0ecbdd3449 143 // Override any currently active haptic effect
roysandberg 0:8c0ecbdd3449 144 void Haptics_OverrideOutputWaveform(const Waveform* newWaveform)
roysandberg 0:8c0ecbdd3449 145 {
roysandberg 0:8c0ecbdd3449 146 //led1 = !led1;
roysandberg 0:8c0ecbdd3449 147 placeInWaveform = 0;
roysandberg 0:8c0ecbdd3449 148 waveform = newWaveform;
roysandberg 0:8c0ecbdd3449 149 LRA_EN = 1;
roysandberg 0:8c0ecbdd3449 150 LRA.pulsewidth_us((((int)waveform->data[placeInWaveform])*3) >> 3); // mult by 3 shift right by 2 to get in range of 0..95
roysandberg 0:8c0ecbdd3449 151 lraPlaybackMode = LRA_MODE_WAVEFORM;
roysandberg 0:8c0ecbdd3449 152 }
roysandberg 0:8c0ecbdd3449 153
roysandberg 0:8c0ecbdd3449 154 void Haptics_OutputDelayedHeartbeat(uint16_t delay) {
roysandberg 0:8c0ecbdd3449 155 Haptics_OutputDelayedWaveform(heartbeatWaveform, delay);
roysandberg 0:8c0ecbdd3449 156 }
roysandberg 0:8c0ecbdd3449 157
roysandberg 0:8c0ecbdd3449 158 void Haptics_SetHeartbeatWaveform (int waveformNum) {
roysandberg 0:8c0ecbdd3449 159 printf("SetHeartbeatWaveform to %d.\n\r", waveformNum);
roysandberg 0:8c0ecbdd3449 160
roysandberg 0:8c0ecbdd3449 161 switch (waveformNum) {
roysandberg 0:8c0ecbdd3449 162 case 1:
roysandberg 0:8c0ecbdd3449 163 heartbeatWaveform = &lra_click_nobrake;
roysandberg 0:8c0ecbdd3449 164 break;
roysandberg 0:8c0ecbdd3449 165 case 2:
roysandberg 0:8c0ecbdd3449 166 heartbeatWaveform = &lra_alert;
roysandberg 0:8c0ecbdd3449 167 break;
roysandberg 0:8c0ecbdd3449 168 case 3:
roysandberg 0:8c0ecbdd3449 169 heartbeatWaveform = &lra_rampup;
roysandberg 0:8c0ecbdd3449 170 break;
roysandberg 0:8c0ecbdd3449 171 case 4:
roysandberg 0:8c0ecbdd3449 172 heartbeatWaveform = &lra_rampdown;
roysandberg 0:8c0ecbdd3449 173 break;
roysandberg 0:8c0ecbdd3449 174 case 5:
roysandberg 0:8c0ecbdd3449 175 heartbeatWaveform = &lra_softclick;
roysandberg 0:8c0ecbdd3449 176 break;
roysandberg 0:8c0ecbdd3449 177 case 6:
roysandberg 0:8c0ecbdd3449 178 heartbeatWaveform = &lra_softbump;
roysandberg 0:8c0ecbdd3449 179 break;
roysandberg 0:8c0ecbdd3449 180 case 7:
roysandberg 0:8c0ecbdd3449 181 heartbeatWaveform = &lra_softalert;
roysandberg 0:8c0ecbdd3449 182 break;
roysandberg 0:8c0ecbdd3449 183 case 8:
roysandberg 0:8c0ecbdd3449 184 heartbeatWaveform = &lra_rampupdoubleclick;
roysandberg 0:8c0ecbdd3449 185 break;
roysandberg 0:8c0ecbdd3449 186 case 0:
roysandberg 0:8c0ecbdd3449 187 default:
roysandberg 0:8c0ecbdd3449 188 heartbeatWaveform = &lra_tick;
roysandberg 0:8c0ecbdd3449 189 }
roysandberg 0:8c0ecbdd3449 190 }
roysandberg 0:8c0ecbdd3449 191
roysandberg 0:8c0ecbdd3449 192 void Haptics_OutputDelayedWaveform(const Waveform* newWaveform, uint16_t delay) {
roysandberg 0:8c0ecbdd3449 193
roysandberg 0:8c0ecbdd3449 194 if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) {
roysandberg 0:8c0ecbdd3449 195 placeInWaveform = 0;
roysandberg 0:8c0ecbdd3449 196 waveformDelayCounter = 0;
roysandberg 0:8c0ecbdd3449 197 lraDelay = delay;
roysandberg 0:8c0ecbdd3449 198 waveform = newWaveform;
roysandberg 0:8c0ecbdd3449 199 lraPlaybackMode = LRA_MODE_DELAYED_WAVEFORM;
roysandberg 0:8c0ecbdd3449 200 } else {
roysandberg 0:8c0ecbdd3449 201 //printf("Haptics: mode=%d, delay=%d, until=%d, place=%d\n\r", lraPlaybackMode, waveformDelayCounter, lraDelay, placeInWaveform);
roysandberg 0:8c0ecbdd3449 202 }
roysandberg 0:8c0ecbdd3449 203 }
roysandberg 2:4f76784f8968 204
roysandberg 2:4f76784f8968 205
roysandberg 2:4f76784f8968 206 void LEDOffCallback() {
roysandberg 2:4f76784f8968 207 led1=0;
roysandberg 2:4f76784f8968 208 }
roysandberg 2:4f76784f8968 209
roysandberg 2:4f76784f8968 210 void BuzzCallback() {
roysandberg 2:4f76784f8968 211 Haptics_OutputWaveform(&lra_alert);
roysandberg 2:4f76784f8968 212 led1 = 1;
roysandberg 2:4f76784f8968 213 }
roysandberg 2:4f76784f8968 214
roysandberg 2:4f76784f8968 215 // generate off mode haptic response
roysandberg 2:4f76784f8968 216 // This is 2 buzzes separated by 300 ms, and 2 led blinks with the same timing.
roysandberg 2:4f76784f8968 217 void LeavingOffModeHapticResponse(int ledFinalState) {
roysandberg 0:8c0ecbdd3449 218
roysandberg 2:4f76784f8968 219 // Turn on LED and generate first buzz
roysandberg 2:4f76784f8968 220 BuzzCallback();
roysandberg 2:4f76784f8968 221
roysandberg 2:4f76784f8968 222 // Setup callback to turn off LED after 50ms
roysandberg 2:4f76784f8968 223 firstLEDOff.attach(&LEDOffCallback,0.05);
roysandberg 2:4f76784f8968 224
roysandberg 2:4f76784f8968 225 // Setup callback to generate second buzz after 300ms, and turn on LED second time
roysandberg 2:4f76784f8968 226 secondBuzz.attach(&BuzzCallback,0.3);
roysandberg 2:4f76784f8968 227
roysandberg 2:4f76784f8968 228 // Setup callback to turn off LED after 350mS
roysandberg 2:4f76784f8968 229 if (ledFinalState == 0) {
roysandberg 2:4f76784f8968 230 secondLEDOff.attach(&LEDOffCallback,0.35);
roysandberg 2:4f76784f8968 231 }
roysandberg 2:4f76784f8968 232 }
roysandberg 2:4f76784f8968 233
roysandberg 2:4f76784f8968 234 void EnteringOffModeHapticResponse() {
roysandberg 2:4f76784f8968 235 Haptics_OutputWaveform(&lra_rampdown);
roysandberg 2:4f76784f8968 236 led1 = 0;
roysandberg 2:4f76784f8968 237 }
roysandberg 2:4f76784f8968 238
roysandberg 0:8c0ecbdd3449 239 // Ignored while waveform is playing or queued. Overridden by waveforms.
roysandberg 0:8c0ecbdd3449 240 void Haptics_SetRampTarget(float amplitude)
roysandberg 0:8c0ecbdd3449 241 {
roysandberg 0:8c0ecbdd3449 242 if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) {
roysandberg 0:8c0ecbdd3449 243 if (lraPlaybackMode == LRA_MODE_OFF) {
roysandberg 0:8c0ecbdd3449 244 lraCurrent = 384; // reset to threshold off if this is the first ramp target
roysandberg 0:8c0ecbdd3449 245 }
roysandberg 0:8c0ecbdd3449 246 if (amplitude > 1.0) amplitude = 1.0;
roysandberg 0:8c0ecbdd3449 247 if (amplitude < 0.0) amplitude = 0.0;
roysandberg 0:8c0ecbdd3449 248 lraTarget = (int) (amplitude*768); // (96 * 8)
roysandberg 0:8c0ecbdd3449 249 lraPlaybackMode = LRA_MODE_RAMP_TO_TARGET;
roysandberg 0:8c0ecbdd3449 250 //printf("Ramp current=%d, target=%d\n\r", lraCurrent>>3, lraTarget>>3);
roysandberg 0:8c0ecbdd3449 251 }
roysandberg 0:8c0ecbdd3449 252 }
roysandberg 0:8c0ecbdd3449 253
roysandberg 0:8c0ecbdd3449 254 // Buzz this many times
roysandberg 0:8c0ecbdd3449 255 void Haptics_OutputCount (uint16_t count) {
roysandberg 0:8c0ecbdd3449 256 switch (count) {
roysandberg 0:8c0ecbdd3449 257 case 1:
roysandberg 0:8c0ecbdd3449 258 Haptics_OutputWaveform(&lra_click_nobrake);
roysandberg 0:8c0ecbdd3449 259 break;
roysandberg 0:8c0ecbdd3449 260 case 2:
roysandberg 0:8c0ecbdd3449 261 Haptics_OutputWaveform(&lra_doubleclick_nobrake);
roysandberg 0:8c0ecbdd3449 262 break;
roysandberg 0:8c0ecbdd3449 263 case 3:
roysandberg 0:8c0ecbdd3449 264 Haptics_OutputWaveform(&lra_tripleclick_nobrake);
roysandberg 0:8c0ecbdd3449 265 break;
roysandberg 0:8c0ecbdd3449 266 }
roysandberg 0:8c0ecbdd3449 267 }
roysandberg 0:8c0ecbdd3449 268
roysandberg 0:8c0ecbdd3449 269 // Stop haptics regardless of mode
roysandberg 0:8c0ecbdd3449 270 void Haptics_Off()
roysandberg 0:8c0ecbdd3449 271 {
roysandberg 0:8c0ecbdd3449 272 lraPlaybackMode = LRA_MODE_OFF;
roysandberg 0:8c0ecbdd3449 273 }
roysandberg 0:8c0ecbdd3449 274
roysandberg 0:8c0ecbdd3449 275 bool isHapticsOff()
roysandberg 0:8c0ecbdd3449 276 {
roysandberg 0:8c0ecbdd3449 277 return (lraPlaybackMode == LRA_MODE_OFF);
roysandberg 0:8c0ecbdd3449 278 }