Fix for hack that worked around iOS app

Committer:
roysandberg
Date:
Wed May 11 02:28:16 2016 +0000
Revision:
5:c9d71618070d
Parent:
4:d3858592d3b5
Version with heart rate 30 second 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 3:b64f3abb3c0b 109 LRA.pulsewidth_us(0);
roysandberg 3:b64f3abb3c0b 110 LRA_EN = 0;
roysandberg 3:b64f3abb3c0b 111 placeInWaveform = 0;
roysandberg 3:b64f3abb3c0b 112 waveformDelayCounter = 0;
roysandberg 0:8c0ecbdd3449 113 break;
roysandberg 0:8c0ecbdd3449 114 }
roysandberg 0:8c0ecbdd3449 115 }
roysandberg 0:8c0ecbdd3449 116
roysandberg 0:8c0ecbdd3449 117 /**
roysandberg 0:8c0ecbdd3449 118 * Haptics_Init - initialize haptics variables and settings
roysandberg 0:8c0ecbdd3449 119 */
roysandberg 0:8c0ecbdd3449 120 void Haptics_Init(void)
roysandberg 0:8c0ecbdd3449 121 {
roysandberg 0:8c0ecbdd3449 122 // mbed uses 4uS timer precision, so keep this as large as possible for better granularity
roysandberg 0:8c0ecbdd3449 123 // 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 124 LRA.period_us(96); // 96 uS -> 10.4 Khz (needs to be between 10Khz and 250Khz)
roysandberg 0:8c0ecbdd3449 125
roysandberg 0:8c0ecbdd3449 126 hapticsTicker.attach(&hapticsCallback, 0.005); // update haptics every 5 ms
roysandberg 0:8c0ecbdd3449 127
roysandberg 0:8c0ecbdd3449 128 Haptics_resonantModeTick = (unsigned int) Haptics_dumbModeTick * 2;
roysandberg 0:8c0ecbdd3449 129 }
roysandberg 0:8c0ecbdd3449 130
roysandberg 0:8c0ecbdd3449 131
roysandberg 0:8c0ecbdd3449 132 /*
roysandberg 0:8c0ecbdd3449 133 * Haptics_OutputWaveform - control the PWM output pattern
roysandberg 0:8c0ecbdd3449 134 * @param struct Waveform - the waveform output type, length in bytes, and data
roysandberg 0:8c0ecbdd3449 135 */
roysandberg 0:8c0ecbdd3449 136 void Haptics_OutputWaveform(const Waveform* newWaveform)
roysandberg 0:8c0ecbdd3449 137 {
roysandberg 0:8c0ecbdd3449 138
roysandberg 0:8c0ecbdd3449 139 if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) {
roysandberg 0:8c0ecbdd3449 140 waveform = newWaveform;
roysandberg 0:8c0ecbdd3449 141 lraPlaybackMode = LRA_MODE_WAVEFORM;
roysandberg 0:8c0ecbdd3449 142 } else {
roysandberg 0:8c0ecbdd3449 143 //printf("OutputWaveform: mode=%d, delay=%d, place=%d\n\r", lraPlaybackMode, waveformDelayCounter, placeInWaveform);
roysandberg 0:8c0ecbdd3449 144 }
roysandberg 0:8c0ecbdd3449 145 }
roysandberg 0:8c0ecbdd3449 146
roysandberg 0:8c0ecbdd3449 147 // Override any currently active haptic effect
roysandberg 0:8c0ecbdd3449 148 void Haptics_OverrideOutputWaveform(const Waveform* newWaveform)
roysandberg 0:8c0ecbdd3449 149 {
roysandberg 0:8c0ecbdd3449 150 //led1 = !led1;
roysandberg 0:8c0ecbdd3449 151 placeInWaveform = 0;
roysandberg 0:8c0ecbdd3449 152 waveform = newWaveform;
roysandberg 0:8c0ecbdd3449 153 LRA_EN = 1;
roysandberg 0:8c0ecbdd3449 154 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 155 lraPlaybackMode = LRA_MODE_WAVEFORM;
roysandberg 0:8c0ecbdd3449 156 }
roysandberg 0:8c0ecbdd3449 157
roysandberg 0:8c0ecbdd3449 158 void Haptics_OutputDelayedHeartbeat(uint16_t delay) {
roysandberg 0:8c0ecbdd3449 159 Haptics_OutputDelayedWaveform(heartbeatWaveform, delay);
roysandberg 0:8c0ecbdd3449 160 }
roysandberg 0:8c0ecbdd3449 161
roysandberg 0:8c0ecbdd3449 162 void Haptics_SetHeartbeatWaveform (int waveformNum) {
roysandberg 0:8c0ecbdd3449 163 printf("SetHeartbeatWaveform to %d.\n\r", waveformNum);
roysandberg 0:8c0ecbdd3449 164
roysandberg 0:8c0ecbdd3449 165 switch (waveformNum) {
roysandberg 0:8c0ecbdd3449 166 case 1:
roysandberg 0:8c0ecbdd3449 167 heartbeatWaveform = &lra_click_nobrake;
roysandberg 0:8c0ecbdd3449 168 break;
roysandberg 0:8c0ecbdd3449 169 case 2:
roysandberg 0:8c0ecbdd3449 170 heartbeatWaveform = &lra_alert;
roysandberg 0:8c0ecbdd3449 171 break;
roysandberg 0:8c0ecbdd3449 172 case 3:
roysandberg 0:8c0ecbdd3449 173 heartbeatWaveform = &lra_rampup;
roysandberg 0:8c0ecbdd3449 174 break;
roysandberg 0:8c0ecbdd3449 175 case 4:
roysandberg 0:8c0ecbdd3449 176 heartbeatWaveform = &lra_rampdown;
roysandberg 0:8c0ecbdd3449 177 break;
roysandberg 0:8c0ecbdd3449 178 case 5:
roysandberg 0:8c0ecbdd3449 179 heartbeatWaveform = &lra_softclick;
roysandberg 0:8c0ecbdd3449 180 break;
roysandberg 0:8c0ecbdd3449 181 case 6:
roysandberg 0:8c0ecbdd3449 182 heartbeatWaveform = &lra_softbump;
roysandberg 0:8c0ecbdd3449 183 break;
roysandberg 0:8c0ecbdd3449 184 case 7:
roysandberg 0:8c0ecbdd3449 185 heartbeatWaveform = &lra_softalert;
roysandberg 0:8c0ecbdd3449 186 break;
roysandberg 0:8c0ecbdd3449 187 case 8:
roysandberg 0:8c0ecbdd3449 188 heartbeatWaveform = &lra_rampupdoubleclick;
roysandberg 0:8c0ecbdd3449 189 break;
roysandberg 0:8c0ecbdd3449 190 case 0:
roysandberg 0:8c0ecbdd3449 191 default:
roysandberg 0:8c0ecbdd3449 192 heartbeatWaveform = &lra_tick;
roysandberg 0:8c0ecbdd3449 193 }
roysandberg 0:8c0ecbdd3449 194 }
roysandberg 0:8c0ecbdd3449 195
roysandberg 0:8c0ecbdd3449 196 void Haptics_OutputDelayedWaveform(const Waveform* newWaveform, uint16_t delay) {
roysandberg 0:8c0ecbdd3449 197
roysandberg 0:8c0ecbdd3449 198 if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) {
roysandberg 0:8c0ecbdd3449 199 placeInWaveform = 0;
roysandberg 0:8c0ecbdd3449 200 waveformDelayCounter = 0;
roysandberg 0:8c0ecbdd3449 201 lraDelay = delay;
roysandberg 0:8c0ecbdd3449 202 waveform = newWaveform;
roysandberg 0:8c0ecbdd3449 203 lraPlaybackMode = LRA_MODE_DELAYED_WAVEFORM;
roysandberg 0:8c0ecbdd3449 204 } else {
roysandberg 0:8c0ecbdd3449 205 //printf("Haptics: mode=%d, delay=%d, until=%d, place=%d\n\r", lraPlaybackMode, waveformDelayCounter, lraDelay, placeInWaveform);
roysandberg 0:8c0ecbdd3449 206 }
roysandberg 0:8c0ecbdd3449 207 }
roysandberg 2:4f76784f8968 208
roysandberg 2:4f76784f8968 209
roysandberg 2:4f76784f8968 210 void LEDOffCallback() {
roysandberg 2:4f76784f8968 211 led1=0;
roysandberg 2:4f76784f8968 212 }
roysandberg 2:4f76784f8968 213
roysandberg 2:4f76784f8968 214 void BuzzCallback() {
roysandberg 2:4f76784f8968 215 Haptics_OutputWaveform(&lra_alert);
roysandberg 2:4f76784f8968 216 led1 = 1;
roysandberg 2:4f76784f8968 217 }
roysandberg 2:4f76784f8968 218
roysandberg 2:4f76784f8968 219 // generate off mode haptic response
roysandberg 2:4f76784f8968 220 // This is 2 buzzes separated by 300 ms, and 2 led blinks with the same timing.
roysandberg 2:4f76784f8968 221 void LeavingOffModeHapticResponse(int ledFinalState) {
roysandberg 0:8c0ecbdd3449 222
roysandberg 2:4f76784f8968 223 // Turn on LED and generate first buzz
roysandberg 2:4f76784f8968 224 BuzzCallback();
roysandberg 2:4f76784f8968 225
roysandberg 2:4f76784f8968 226 // Setup callback to turn off LED after 50ms
roysandberg 2:4f76784f8968 227 firstLEDOff.attach(&LEDOffCallback,0.05);
roysandberg 2:4f76784f8968 228
roysandberg 2:4f76784f8968 229 // Setup callback to generate second buzz after 300ms, and turn on LED second time
roysandberg 2:4f76784f8968 230 secondBuzz.attach(&BuzzCallback,0.3);
roysandberg 2:4f76784f8968 231
roysandberg 2:4f76784f8968 232 // Setup callback to turn off LED after 350mS
roysandberg 2:4f76784f8968 233 if (ledFinalState == 0) {
roysandberg 2:4f76784f8968 234 secondLEDOff.attach(&LEDOffCallback,0.35);
roysandberg 2:4f76784f8968 235 }
roysandberg 2:4f76784f8968 236 }
roysandberg 2:4f76784f8968 237
roysandberg 2:4f76784f8968 238 void EnteringOffModeHapticResponse() {
roysandberg 2:4f76784f8968 239 Haptics_OutputWaveform(&lra_rampdown);
roysandberg 2:4f76784f8968 240 led1 = 0;
roysandberg 2:4f76784f8968 241 }
roysandberg 2:4f76784f8968 242
roysandberg 0:8c0ecbdd3449 243 // Ignored while waveform is playing or queued. Overridden by waveforms.
roysandberg 0:8c0ecbdd3449 244 void Haptics_SetRampTarget(float amplitude)
roysandberg 0:8c0ecbdd3449 245 {
roysandberg 0:8c0ecbdd3449 246 if (lraPlaybackMode == LRA_MODE_OFF || lraPlaybackMode == LRA_MODE_RAMP_TO_TARGET) {
roysandberg 0:8c0ecbdd3449 247 if (lraPlaybackMode == LRA_MODE_OFF) {
roysandberg 0:8c0ecbdd3449 248 lraCurrent = 384; // reset to threshold off if this is the first ramp target
roysandberg 0:8c0ecbdd3449 249 }
roysandberg 0:8c0ecbdd3449 250 if (amplitude > 1.0) amplitude = 1.0;
roysandberg 0:8c0ecbdd3449 251 if (amplitude < 0.0) amplitude = 0.0;
roysandberg 0:8c0ecbdd3449 252 lraTarget = (int) (amplitude*768); // (96 * 8)
roysandberg 0:8c0ecbdd3449 253 lraPlaybackMode = LRA_MODE_RAMP_TO_TARGET;
roysandberg 0:8c0ecbdd3449 254 //printf("Ramp current=%d, target=%d\n\r", lraCurrent>>3, lraTarget>>3);
roysandberg 0:8c0ecbdd3449 255 }
roysandberg 0:8c0ecbdd3449 256 }
roysandberg 0:8c0ecbdd3449 257
roysandberg 0:8c0ecbdd3449 258 // Buzz this many times
roysandberg 0:8c0ecbdd3449 259 void Haptics_OutputCount (uint16_t count) {
roysandberg 0:8c0ecbdd3449 260 switch (count) {
roysandberg 0:8c0ecbdd3449 261 case 1:
roysandberg 0:8c0ecbdd3449 262 Haptics_OutputWaveform(&lra_click_nobrake);
roysandberg 0:8c0ecbdd3449 263 break;
roysandberg 0:8c0ecbdd3449 264 case 2:
roysandberg 0:8c0ecbdd3449 265 Haptics_OutputWaveform(&lra_doubleclick_nobrake);
roysandberg 0:8c0ecbdd3449 266 break;
roysandberg 0:8c0ecbdd3449 267 case 3:
roysandberg 0:8c0ecbdd3449 268 Haptics_OutputWaveform(&lra_tripleclick_nobrake);
roysandberg 0:8c0ecbdd3449 269 break;
roysandberg 4:d3858592d3b5 270 case 4:
roysandberg 4:d3858592d3b5 271 Haptics_OutputWaveform(&lra_quarupleclick_nobrake);
roysandberg 4:d3858592d3b5 272 break;
roysandberg 0:8c0ecbdd3449 273 }
roysandberg 0:8c0ecbdd3449 274 }
roysandberg 0:8c0ecbdd3449 275
roysandberg 0:8c0ecbdd3449 276 // Stop haptics regardless of mode
roysandberg 0:8c0ecbdd3449 277 void Haptics_Off()
roysandberg 0:8c0ecbdd3449 278 {
roysandberg 0:8c0ecbdd3449 279 lraPlaybackMode = LRA_MODE_OFF;
roysandberg 0:8c0ecbdd3449 280 }
roysandberg 0:8c0ecbdd3449 281
roysandberg 0:8c0ecbdd3449 282 bool isHapticsOff()
roysandberg 0:8c0ecbdd3449 283 {
roysandberg 0:8c0ecbdd3449 284 return (lraPlaybackMode == LRA_MODE_OFF);
roysandberg 0:8c0ecbdd3449 285 }