work in progress
Dependencies: FastAnalogIn FastIO USBDevice mbed FastPWM SimpleDMA
Fork of Pinscape_Controller by
main.cpp@1:d913e0afb2ac, 2014-07-16 (annotated)
- Committer:
- mjr
- Date:
- Wed Jul 16 23:33:12 2014 +0000
- Revision:
- 1:d913e0afb2ac
- Parent:
- 0:5acbbe3f4cf4
- Child:
- 2:c174f9ee414a
Before removing time/frequency limit on reading the plunger sensor
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 0:5acbbe3f4cf4 | 1 | #include "mbed.h" |
mjr | 0:5acbbe3f4cf4 | 2 | #include "USBJoystick.h" |
mjr | 0:5acbbe3f4cf4 | 3 | #include "MMA8451Q.h" |
mjr | 1:d913e0afb2ac | 4 | #include "tsl1410r.h" |
mjr | 1:d913e0afb2ac | 5 | #include "FreescaleIAP.h" |
mjr | 0:5acbbe3f4cf4 | 6 | |
mjr | 1:d913e0afb2ac | 7 | // on-board RGB LED elements - we use these for diagnostics |
mjr | 0:5acbbe3f4cf4 | 8 | PwmOut led1(LED1), led2(LED2), led3(LED3); |
mjr | 0:5acbbe3f4cf4 | 9 | |
mjr | 1:d913e0afb2ac | 10 | // calibration button - switch input and LED output |
mjr | 1:d913e0afb2ac | 11 | DigitalIn calBtn(PTE29); |
mjr | 1:d913e0afb2ac | 12 | DigitalOut calBtnLed(PTE23); |
mjr | 0:5acbbe3f4cf4 | 13 | |
mjr | 0:5acbbe3f4cf4 | 14 | static int pbaIdx = 0; |
mjr | 0:5acbbe3f4cf4 | 15 | |
mjr | 0:5acbbe3f4cf4 | 16 | // on/off state for each LedWiz output |
mjr | 1:d913e0afb2ac | 17 | static uint8_t wizOn[32]; |
mjr | 0:5acbbe3f4cf4 | 18 | |
mjr | 0:5acbbe3f4cf4 | 19 | // profile (brightness/blink) state for each LedWiz output |
mjr | 1:d913e0afb2ac | 20 | static uint8_t wizVal[32] = { |
mjr | 0:5acbbe3f4cf4 | 21 | 0, 0, 0, 0, 0, 0, 0, 0, |
mjr | 0:5acbbe3f4cf4 | 22 | 0, 0, 0, 0, 0, 0, 0, 0, |
mjr | 0:5acbbe3f4cf4 | 23 | 0, 0, 0, 0, 0, 0, 0, 0, |
mjr | 0:5acbbe3f4cf4 | 24 | 0, 0, 0, 0, 0, 0, 0, 0 |
mjr | 0:5acbbe3f4cf4 | 25 | }; |
mjr | 0:5acbbe3f4cf4 | 26 | |
mjr | 1:d913e0afb2ac | 27 | static float wizState(int idx) |
mjr | 0:5acbbe3f4cf4 | 28 | { |
mjr | 1:d913e0afb2ac | 29 | if (wizOn[idx]) { |
mjr | 0:5acbbe3f4cf4 | 30 | // on - map profile brightness state to PWM level |
mjr | 1:d913e0afb2ac | 31 | uint8_t val = wizVal[idx]; |
mjr | 0:5acbbe3f4cf4 | 32 | if (val >= 1 && val <= 48) |
mjr | 0:5acbbe3f4cf4 | 33 | return 1.0 - val/48.0; |
mjr | 0:5acbbe3f4cf4 | 34 | else if (val >= 129 && val <= 132) |
mjr | 0:5acbbe3f4cf4 | 35 | return 0.0; |
mjr | 0:5acbbe3f4cf4 | 36 | else |
mjr | 0:5acbbe3f4cf4 | 37 | return 1.0; |
mjr | 0:5acbbe3f4cf4 | 38 | } |
mjr | 0:5acbbe3f4cf4 | 39 | else { |
mjr | 0:5acbbe3f4cf4 | 40 | // off |
mjr | 0:5acbbe3f4cf4 | 41 | return 1.0; |
mjr | 0:5acbbe3f4cf4 | 42 | } |
mjr | 0:5acbbe3f4cf4 | 43 | } |
mjr | 0:5acbbe3f4cf4 | 44 | |
mjr | 1:d913e0afb2ac | 45 | static void updateWizOuts() |
mjr | 1:d913e0afb2ac | 46 | { |
mjr | 1:d913e0afb2ac | 47 | led1 = wizState(0); |
mjr | 1:d913e0afb2ac | 48 | led2 = wizState(1); |
mjr | 1:d913e0afb2ac | 49 | led3 = wizState(2); |
mjr | 1:d913e0afb2ac | 50 | } |
mjr | 1:d913e0afb2ac | 51 | |
mjr | 1:d913e0afb2ac | 52 | struct AccPrv |
mjr | 0:5acbbe3f4cf4 | 53 | { |
mjr | 1:d913e0afb2ac | 54 | AccPrv() : x(0), y(0) { } |
mjr | 1:d913e0afb2ac | 55 | float x; |
mjr | 1:d913e0afb2ac | 56 | float y; |
mjr | 1:d913e0afb2ac | 57 | |
mjr | 1:d913e0afb2ac | 58 | double dist(AccPrv &b) |
mjr | 1:d913e0afb2ac | 59 | { |
mjr | 1:d913e0afb2ac | 60 | float dx = x - b.x, dy = y - b.y; |
mjr | 1:d913e0afb2ac | 61 | return sqrt(dx*dx + dy*dy); |
mjr | 1:d913e0afb2ac | 62 | } |
mjr | 1:d913e0afb2ac | 63 | }; |
mjr | 0:5acbbe3f4cf4 | 64 | |
mjr | 0:5acbbe3f4cf4 | 65 | int main(void) |
mjr | 0:5acbbe3f4cf4 | 66 | { |
mjr | 1:d913e0afb2ac | 67 | // turn off our on-board indicator LED |
mjr | 0:5acbbe3f4cf4 | 68 | led1 = 1; |
mjr | 0:5acbbe3f4cf4 | 69 | led2 = 1; |
mjr | 0:5acbbe3f4cf4 | 70 | led3 = 1; |
mjr | 1:d913e0afb2ac | 71 | |
mjr | 1:d913e0afb2ac | 72 | // plunger calibration data |
mjr | 1:d913e0afb2ac | 73 | const int npix = 320; |
mjr | 1:d913e0afb2ac | 74 | int plungerMin = 0, plungerMax = npix; |
mjr | 1:d913e0afb2ac | 75 | |
mjr | 1:d913e0afb2ac | 76 | // plunger calibration button debounce timer |
mjr | 1:d913e0afb2ac | 77 | Timer calBtnTimer; |
mjr | 1:d913e0afb2ac | 78 | calBtnTimer.start(); |
mjr | 1:d913e0afb2ac | 79 | int calBtnDownTime = 0; |
mjr | 1:d913e0afb2ac | 80 | int calBtnLit = false; |
mjr | 1:d913e0afb2ac | 81 | |
mjr | 1:d913e0afb2ac | 82 | // Calibration button state: |
mjr | 1:d913e0afb2ac | 83 | // 0 = not pushed |
mjr | 1:d913e0afb2ac | 84 | // 1 = pushed, not yet debounced |
mjr | 1:d913e0afb2ac | 85 | // 2 = pushed, debounced, waiting for hold time |
mjr | 1:d913e0afb2ac | 86 | // 3 = pushed, hold time completed - in calibration mode |
mjr | 1:d913e0afb2ac | 87 | int calBtnState = 0; |
mjr | 1:d913e0afb2ac | 88 | |
mjr | 1:d913e0afb2ac | 89 | // set up a timer for our heartbeat indicator |
mjr | 1:d913e0afb2ac | 90 | Timer hbTimer; |
mjr | 1:d913e0afb2ac | 91 | hbTimer.start(); |
mjr | 1:d913e0afb2ac | 92 | int t0Hb = hbTimer.read_ms(); |
mjr | 1:d913e0afb2ac | 93 | int hb = 0; |
mjr | 1:d913e0afb2ac | 94 | |
mjr | 1:d913e0afb2ac | 95 | // set a timer for accelerometer auto-centering |
mjr | 1:d913e0afb2ac | 96 | Timer acTimer; |
mjr | 1:d913e0afb2ac | 97 | acTimer.start(); |
mjr | 1:d913e0afb2ac | 98 | int t0ac = acTimer.read_ms(); |
mjr | 1:d913e0afb2ac | 99 | |
mjr | 1:d913e0afb2ac | 100 | // set up a timer for reading the plunger sensor |
mjr | 1:d913e0afb2ac | 101 | Timer ccdTimer; |
mjr | 1:d913e0afb2ac | 102 | ccdTimer.start(); |
mjr | 1:d913e0afb2ac | 103 | int t0ccd = ccdTimer.read_ms(); |
mjr | 1:d913e0afb2ac | 104 | |
mjr | 1:d913e0afb2ac | 105 | #if 0 |
mjr | 1:d913e0afb2ac | 106 | // DEBUG |
mjr | 1:d913e0afb2ac | 107 | Timer ccdDbgTimer; |
mjr | 1:d913e0afb2ac | 108 | ccdDbgTimer.start(); |
mjr | 1:d913e0afb2ac | 109 | int t0ccdDbg = ccdDbgTimer.read_ms(); |
mjr | 1:d913e0afb2ac | 110 | #endif |
mjr | 0:5acbbe3f4cf4 | 111 | |
mjr | 1:d913e0afb2ac | 112 | // Create the joystick USB client. Light the on-board indicator LED |
mjr | 1:d913e0afb2ac | 113 | // red while connecting, and change to green after we connect. |
mjr | 0:5acbbe3f4cf4 | 114 | led1 = 0.75; |
mjr | 0:5acbbe3f4cf4 | 115 | USBJoystick js(0xFAFA, 0x00F7, 0x0001); |
mjr | 0:5acbbe3f4cf4 | 116 | led1 = 1; |
mjr | 0:5acbbe3f4cf4 | 117 | led2 = 0.75; |
mjr | 0:5acbbe3f4cf4 | 118 | |
mjr | 0:5acbbe3f4cf4 | 119 | // create the accelerometer object |
mjr | 0:5acbbe3f4cf4 | 120 | const int MMA8451_I2C_ADDRESS = (0x1d<<1); |
mjr | 0:5acbbe3f4cf4 | 121 | MMA8451Q accel(PTE25, PTE24, MMA8451_I2C_ADDRESS); |
mjr | 0:5acbbe3f4cf4 | 122 | |
mjr | 0:5acbbe3f4cf4 | 123 | // create the CCD array object |
mjr | 1:d913e0afb2ac | 124 | TSL1410R ccd(PTE20, PTE21, PTB0); |
mjr | 1:d913e0afb2ac | 125 | |
mjr | 1:d913e0afb2ac | 126 | // recent accelerometer readings, for auto centering |
mjr | 1:d913e0afb2ac | 127 | int iAccPrv = 0, nAccPrv = 0; |
mjr | 1:d913e0afb2ac | 128 | const int maxAccPrv = 5; |
mjr | 1:d913e0afb2ac | 129 | AccPrv accPrv[maxAccPrv]; |
mjr | 0:5acbbe3f4cf4 | 130 | |
mjr | 1:d913e0afb2ac | 131 | // last accelerometer report, in mouse coordinates |
mjr | 1:d913e0afb2ac | 132 | int x = 127, y = 127, z = 0; |
mjr | 1:d913e0afb2ac | 133 | |
mjr | 1:d913e0afb2ac | 134 | // raw accelerator centerpoint, on the unit interval (-1.0 .. +1.0) |
mjr | 1:d913e0afb2ac | 135 | float xCenter = 0.0, yCenter = 0.0; |
mjr | 1:d913e0afb2ac | 136 | |
mjr | 1:d913e0afb2ac | 137 | // we're all set up - now just loop, processing sensor reports and |
mjr | 1:d913e0afb2ac | 138 | // host requests |
mjr | 0:5acbbe3f4cf4 | 139 | for (;;) |
mjr | 0:5acbbe3f4cf4 | 140 | { |
mjr | 0:5acbbe3f4cf4 | 141 | // Look for an incoming report. Continue processing input as |
mjr | 0:5acbbe3f4cf4 | 142 | // long as there's anything pending - this ensures that we |
mjr | 0:5acbbe3f4cf4 | 143 | // handle input in as timely a fashion as possible by deferring |
mjr | 0:5acbbe3f4cf4 | 144 | // output tasks as long as there's input to process. |
mjr | 0:5acbbe3f4cf4 | 145 | HID_REPORT report; |
mjr | 0:5acbbe3f4cf4 | 146 | while (js.readNB(&report) && report.length == 8) |
mjr | 0:5acbbe3f4cf4 | 147 | { |
mjr | 0:5acbbe3f4cf4 | 148 | uint8_t *data = report.data; |
mjr | 1:d913e0afb2ac | 149 | if (data[0] == 64) |
mjr | 1:d913e0afb2ac | 150 | { |
mjr | 0:5acbbe3f4cf4 | 151 | // LWZ-SBA - first four bytes are bit-packed on/off flags |
mjr | 0:5acbbe3f4cf4 | 152 | // for the outputs; 5th byte is the pulse speed (0-7) |
mjr | 0:5acbbe3f4cf4 | 153 | //printf("LWZ-SBA %02x %02x %02x %02x ; %02x\r\n", |
mjr | 0:5acbbe3f4cf4 | 154 | // data[1], data[2], data[3], data[4], data[5]); |
mjr | 0:5acbbe3f4cf4 | 155 | |
mjr | 0:5acbbe3f4cf4 | 156 | // update all on/off states |
mjr | 0:5acbbe3f4cf4 | 157 | for (int i = 0, bit = 1, ri = 1 ; i < 32 ; ++i, bit <<= 1) |
mjr | 0:5acbbe3f4cf4 | 158 | { |
mjr | 0:5acbbe3f4cf4 | 159 | if (bit == 0x100) { |
mjr | 0:5acbbe3f4cf4 | 160 | bit = 1; |
mjr | 0:5acbbe3f4cf4 | 161 | ++ri; |
mjr | 0:5acbbe3f4cf4 | 162 | } |
mjr | 1:d913e0afb2ac | 163 | wizOn[i] = ((data[ri] & bit) != 0); |
mjr | 0:5acbbe3f4cf4 | 164 | } |
mjr | 0:5acbbe3f4cf4 | 165 | |
mjr | 1:d913e0afb2ac | 166 | // update the physical outputs |
mjr | 1:d913e0afb2ac | 167 | updateWizOuts(); |
mjr | 0:5acbbe3f4cf4 | 168 | |
mjr | 0:5acbbe3f4cf4 | 169 | // reset the PBA counter |
mjr | 0:5acbbe3f4cf4 | 170 | pbaIdx = 0; |
mjr | 0:5acbbe3f4cf4 | 171 | } |
mjr | 1:d913e0afb2ac | 172 | else |
mjr | 1:d913e0afb2ac | 173 | { |
mjr | 0:5acbbe3f4cf4 | 174 | // LWZ-PBA - full state dump; each byte is one output |
mjr | 0:5acbbe3f4cf4 | 175 | // in the current bank. pbaIdx keeps track of the bank; |
mjr | 0:5acbbe3f4cf4 | 176 | // this is incremented implicitly by each PBA message. |
mjr | 0:5acbbe3f4cf4 | 177 | //printf("LWZ-PBA[%d] %02x %02x %02x %02x %02x %02x %02x %02x\r\n", |
mjr | 0:5acbbe3f4cf4 | 178 | // pbaIdx, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); |
mjr | 0:5acbbe3f4cf4 | 179 | |
mjr | 0:5acbbe3f4cf4 | 180 | // update all output profile settings |
mjr | 0:5acbbe3f4cf4 | 181 | for (int i = 0 ; i < 8 ; ++i) |
mjr | 1:d913e0afb2ac | 182 | wizVal[pbaIdx + i] = data[i]; |
mjr | 0:5acbbe3f4cf4 | 183 | |
mjr | 0:5acbbe3f4cf4 | 184 | // update the physical LED state if this is the last bank |
mjr | 0:5acbbe3f4cf4 | 185 | if (pbaIdx == 24) |
mjr | 1:d913e0afb2ac | 186 | updateWizOuts(); |
mjr | 0:5acbbe3f4cf4 | 187 | |
mjr | 0:5acbbe3f4cf4 | 188 | // advance to the next bank |
mjr | 0:5acbbe3f4cf4 | 189 | pbaIdx = (pbaIdx + 8) & 31; |
mjr | 0:5acbbe3f4cf4 | 190 | } |
mjr | 0:5acbbe3f4cf4 | 191 | } |
mjr | 1:d913e0afb2ac | 192 | |
mjr | 1:d913e0afb2ac | 193 | // check for plunger calibration |
mjr | 1:d913e0afb2ac | 194 | if (!calBtn) |
mjr | 0:5acbbe3f4cf4 | 195 | { |
mjr | 1:d913e0afb2ac | 196 | // check the state |
mjr | 1:d913e0afb2ac | 197 | switch (calBtnState) |
mjr | 0:5acbbe3f4cf4 | 198 | { |
mjr | 1:d913e0afb2ac | 199 | case 0: |
mjr | 1:d913e0afb2ac | 200 | // button not yet pushed - start debouncing |
mjr | 1:d913e0afb2ac | 201 | calBtnTimer.reset(); |
mjr | 1:d913e0afb2ac | 202 | calBtnDownTime = calBtnTimer.read_ms(); |
mjr | 1:d913e0afb2ac | 203 | calBtnState = 1; |
mjr | 1:d913e0afb2ac | 204 | break; |
mjr | 1:d913e0afb2ac | 205 | |
mjr | 1:d913e0afb2ac | 206 | case 1: |
mjr | 1:d913e0afb2ac | 207 | // pushed, not yet debounced - if the debounce time has |
mjr | 1:d913e0afb2ac | 208 | // passed, start the hold period |
mjr | 1:d913e0afb2ac | 209 | if (calBtnTimer.read_ms() - calBtnDownTime > 50) |
mjr | 1:d913e0afb2ac | 210 | calBtnState = 2; |
mjr | 1:d913e0afb2ac | 211 | break; |
mjr | 1:d913e0afb2ac | 212 | |
mjr | 1:d913e0afb2ac | 213 | case 2: |
mjr | 1:d913e0afb2ac | 214 | // in the hold period - if the button has been held down |
mjr | 1:d913e0afb2ac | 215 | // for the entire hold period, move to calibration mode |
mjr | 1:d913e0afb2ac | 216 | if (calBtnTimer.read_ms() - calBtnDownTime > 2050) |
mjr | 1:d913e0afb2ac | 217 | { |
mjr | 1:d913e0afb2ac | 218 | // enter calibration mode |
mjr | 1:d913e0afb2ac | 219 | calBtnState = 3; |
mjr | 1:d913e0afb2ac | 220 | |
mjr | 1:d913e0afb2ac | 221 | // reset the calibration limits |
mjr | 1:d913e0afb2ac | 222 | plungerMax = 0; |
mjr | 1:d913e0afb2ac | 223 | plungerMin = npix; |
mjr | 1:d913e0afb2ac | 224 | } |
mjr | 1:d913e0afb2ac | 225 | break; |
mjr | 0:5acbbe3f4cf4 | 226 | } |
mjr | 0:5acbbe3f4cf4 | 227 | } |
mjr | 1:d913e0afb2ac | 228 | else |
mjr | 1:d913e0afb2ac | 229 | { |
mjr | 1:d913e0afb2ac | 230 | // Button released. If we're not already in calibration mode, |
mjr | 1:d913e0afb2ac | 231 | // reset the button state. Once calibration mode starts, it sticks |
mjr | 1:d913e0afb2ac | 232 | // until the calibration time elapses. |
mjr | 1:d913e0afb2ac | 233 | if (calBtnState != 3) |
mjr | 1:d913e0afb2ac | 234 | calBtnState = 0; |
mjr | 1:d913e0afb2ac | 235 | else if (calBtnTimer.read_ms() - calBtnDownTime > 32500) |
mjr | 1:d913e0afb2ac | 236 | calBtnState = 0; |
mjr | 1:d913e0afb2ac | 237 | } |
mjr | 1:d913e0afb2ac | 238 | |
mjr | 1:d913e0afb2ac | 239 | // light/flash the calibration button light, if applicable |
mjr | 1:d913e0afb2ac | 240 | int newCalBtnLit = calBtnLit; |
mjr | 1:d913e0afb2ac | 241 | switch (calBtnState) |
mjr | 0:5acbbe3f4cf4 | 242 | { |
mjr | 1:d913e0afb2ac | 243 | case 2: |
mjr | 1:d913e0afb2ac | 244 | // in the hold period - flash the light |
mjr | 1:d913e0afb2ac | 245 | newCalBtnLit = (((calBtnTimer.read_ms() - calBtnDownTime)/250) & 1); |
mjr | 1:d913e0afb2ac | 246 | break; |
mjr | 1:d913e0afb2ac | 247 | |
mjr | 1:d913e0afb2ac | 248 | case 3: |
mjr | 1:d913e0afb2ac | 249 | // calibration mode - show steady on |
mjr | 1:d913e0afb2ac | 250 | newCalBtnLit = true; |
mjr | 1:d913e0afb2ac | 251 | break; |
mjr | 1:d913e0afb2ac | 252 | |
mjr | 1:d913e0afb2ac | 253 | default: |
mjr | 1:d913e0afb2ac | 254 | // not calibrating/holding - show steady off |
mjr | 1:d913e0afb2ac | 255 | newCalBtnLit = false; |
mjr | 1:d913e0afb2ac | 256 | break; |
mjr | 1:d913e0afb2ac | 257 | } |
mjr | 1:d913e0afb2ac | 258 | if (calBtnLit != newCalBtnLit) |
mjr | 1:d913e0afb2ac | 259 | { |
mjr | 1:d913e0afb2ac | 260 | calBtnLit = newCalBtnLit; |
mjr | 1:d913e0afb2ac | 261 | calBtnLed = (calBtnLit ? 1 : 0); |
mjr | 1:d913e0afb2ac | 262 | } |
mjr | 1:d913e0afb2ac | 263 | |
mjr | 1:d913e0afb2ac | 264 | // read the plunger sensor |
mjr | 1:d913e0afb2ac | 265 | int znew = z; |
mjr | 1:d913e0afb2ac | 266 | /* if (ccdTimer.read_ms() - t0ccd > 33) */ |
mjr | 1:d913e0afb2ac | 267 | { |
mjr | 1:d913e0afb2ac | 268 | // read the sensor at reduced resolution |
mjr | 1:d913e0afb2ac | 269 | uint16_t pix[npix]; |
mjr | 1:d913e0afb2ac | 270 | ccd.read(pix, npix, 0); |
mjr | 1:d913e0afb2ac | 271 | |
mjr | 1:d913e0afb2ac | 272 | #if 0 |
mjr | 1:d913e0afb2ac | 273 | // debug - send samples every 5 seconds |
mjr | 1:d913e0afb2ac | 274 | if (ccdDbgTimer.read_ms() - t0ccdDbg > 5000) |
mjr | 1:d913e0afb2ac | 275 | { |
mjr | 1:d913e0afb2ac | 276 | for (int i = 0 ; i < npix ; ++i) |
mjr | 1:d913e0afb2ac | 277 | printf("%x ", pix[i]); |
mjr | 1:d913e0afb2ac | 278 | printf("\r\n\r\n"); |
mjr | 1:d913e0afb2ac | 279 | |
mjr | 1:d913e0afb2ac | 280 | ccdDbgTimer.reset(); |
mjr | 1:d913e0afb2ac | 281 | t0ccdDbg = ccdDbgTimer.read_ms(); |
mjr | 0:5acbbe3f4cf4 | 282 | } |
mjr | 1:d913e0afb2ac | 283 | #endif |
mjr | 1:d913e0afb2ac | 284 | |
mjr | 1:d913e0afb2ac | 285 | // check which end is the brighter - this is the "tip" end |
mjr | 1:d913e0afb2ac | 286 | // of the plunger |
mjr | 1:d913e0afb2ac | 287 | long avg1 = (long(pix[0]) + long(pix[1]) + long(pix[2]) + long(pix[3]) + long(pix[4]))/5; |
mjr | 1:d913e0afb2ac | 288 | long avg2 = (long(pix[npix-1]) + long(pix[npix-2]) + long(pix[npix-3]) + long(pix[npix-4]) + long(pix[npix-5]))/5; |
mjr | 1:d913e0afb2ac | 289 | |
mjr | 1:d913e0afb2ac | 290 | // figure the midpoint in the brightness |
mjr | 1:d913e0afb2ac | 291 | long midpt = (avg1 + avg2)/2 * 3; |
mjr | 1:d913e0afb2ac | 292 | |
mjr | 1:d913e0afb2ac | 293 | // Work from the bright end to the dark end. VP interprets the |
mjr | 1:d913e0afb2ac | 294 | // Z axis value as the amount the plunger is pulled: the minimum |
mjr | 1:d913e0afb2ac | 295 | // is the rest position, the maximum is fully pulled. So we |
mjr | 1:d913e0afb2ac | 296 | // essentially want to report how much of the sensor is lit, |
mjr | 1:d913e0afb2ac | 297 | // since this increases as the plunger is pulled back. |
mjr | 1:d913e0afb2ac | 298 | int si = 1, di = 1; |
mjr | 1:d913e0afb2ac | 299 | if (avg1 < avg2) |
mjr | 1:d913e0afb2ac | 300 | si = npix - 1, di = -1; |
mjr | 0:5acbbe3f4cf4 | 301 | |
mjr | 1:d913e0afb2ac | 302 | // scan for the midpoint |
mjr | 1:d913e0afb2ac | 303 | for (int n = 1, i = si ; n < npix - 1 ; ++n, i += di) |
mjr | 1:d913e0afb2ac | 304 | { |
mjr | 1:d913e0afb2ac | 305 | // if we've crossed the midpoint, report this position |
mjr | 1:d913e0afb2ac | 306 | if (long(pix[i-1]) + long(pix[i]) + long(pix[i+1]) < midpt) |
mjr | 1:d913e0afb2ac | 307 | { |
mjr | 1:d913e0afb2ac | 308 | // note the new position |
mjr | 1:d913e0afb2ac | 309 | int pos = abs(i - si); |
mjr | 1:d913e0afb2ac | 310 | |
mjr | 1:d913e0afb2ac | 311 | // Calibrate, or apply calibration, depending on the mode. |
mjr | 1:d913e0afb2ac | 312 | // In either case, normalize to a 0-127 range. VP appears to |
mjr | 1:d913e0afb2ac | 313 | // ignore negative Z axis values. |
mjr | 1:d913e0afb2ac | 314 | if (calBtnState == 3) |
mjr | 1:d913e0afb2ac | 315 | { |
mjr | 1:d913e0afb2ac | 316 | // calibrating - note if we're expanding the calibration envelope |
mjr | 1:d913e0afb2ac | 317 | if (pos < plungerMin) |
mjr | 1:d913e0afb2ac | 318 | plungerMin = pos; |
mjr | 1:d913e0afb2ac | 319 | if (pos > plungerMax) |
mjr | 1:d913e0afb2ac | 320 | plungerMax = pos; |
mjr | 1:d913e0afb2ac | 321 | |
mjr | 1:d913e0afb2ac | 322 | // normalize to the full physical range while calibrating |
mjr | 1:d913e0afb2ac | 323 | znew = int(float(pos)/npix * 127); |
mjr | 1:d913e0afb2ac | 324 | } |
mjr | 1:d913e0afb2ac | 325 | else |
mjr | 1:d913e0afb2ac | 326 | { |
mjr | 1:d913e0afb2ac | 327 | // running normally - normalize to the calibration range |
mjr | 1:d913e0afb2ac | 328 | if (pos < plungerMin) |
mjr | 1:d913e0afb2ac | 329 | pos = plungerMin; |
mjr | 1:d913e0afb2ac | 330 | if (pos > plungerMax) |
mjr | 1:d913e0afb2ac | 331 | pos = plungerMax; |
mjr | 1:d913e0afb2ac | 332 | znew = int(float(pos - plungerMin)/(plungerMax - plungerMin + 1) * 127); |
mjr | 1:d913e0afb2ac | 333 | } |
mjr | 1:d913e0afb2ac | 334 | |
mjr | 1:d913e0afb2ac | 335 | // done |
mjr | 1:d913e0afb2ac | 336 | break; |
mjr | 1:d913e0afb2ac | 337 | } |
mjr | 1:d913e0afb2ac | 338 | } |
mjr | 1:d913e0afb2ac | 339 | |
mjr | 1:d913e0afb2ac | 340 | // reset the timer |
mjr | 1:d913e0afb2ac | 341 | ccdTimer.reset(); |
mjr | 1:d913e0afb2ac | 342 | t0ccd = ccdTimer.read_ms(); |
mjr | 1:d913e0afb2ac | 343 | } |
mjr | 1:d913e0afb2ac | 344 | |
mjr | 1:d913e0afb2ac | 345 | // read the accelerometer |
mjr | 1:d913e0afb2ac | 346 | float xa, ya; |
mjr | 1:d913e0afb2ac | 347 | accel.getAccXY(xa, ya); |
mjr | 1:d913e0afb2ac | 348 | |
mjr | 1:d913e0afb2ac | 349 | // check for auto-centering every so often |
mjr | 1:d913e0afb2ac | 350 | if (acTimer.read_ms() - t0ac > 1000) |
mjr | 1:d913e0afb2ac | 351 | { |
mjr | 1:d913e0afb2ac | 352 | // add the sample to the history list |
mjr | 1:d913e0afb2ac | 353 | accPrv[iAccPrv].x = xa; |
mjr | 1:d913e0afb2ac | 354 | accPrv[iAccPrv].y = ya; |
mjr | 1:d913e0afb2ac | 355 | |
mjr | 1:d913e0afb2ac | 356 | // store the slot |
mjr | 1:d913e0afb2ac | 357 | iAccPrv += 1; |
mjr | 1:d913e0afb2ac | 358 | iAccPrv %= maxAccPrv; |
mjr | 1:d913e0afb2ac | 359 | nAccPrv += 1; |
mjr | 1:d913e0afb2ac | 360 | |
mjr | 1:d913e0afb2ac | 361 | // If we have a full complement, check for stability. The |
mjr | 1:d913e0afb2ac | 362 | // raw accelerometer input is in the rnage -4096 to 4096, but |
mjr | 1:d913e0afb2ac | 363 | // the class cover normalizes to a unit interval (-1.0 .. +1.0). |
mjr | 1:d913e0afb2ac | 364 | const float accTol = .005; |
mjr | 1:d913e0afb2ac | 365 | if (nAccPrv >= maxAccPrv |
mjr | 1:d913e0afb2ac | 366 | && accPrv[0].dist(accPrv[1]) < accTol |
mjr | 1:d913e0afb2ac | 367 | && accPrv[0].dist(accPrv[2]) < accTol |
mjr | 1:d913e0afb2ac | 368 | && accPrv[0].dist(accPrv[3]) < accTol |
mjr | 1:d913e0afb2ac | 369 | && accPrv[0].dist(accPrv[4]) < accTol) |
mjr | 1:d913e0afb2ac | 370 | { |
mjr | 1:d913e0afb2ac | 371 | // figure the new center |
mjr | 1:d913e0afb2ac | 372 | xCenter = (accPrv[0].x + accPrv[1].x + accPrv[2].x + accPrv[3].x + accPrv[4].x)/5.0; |
mjr | 1:d913e0afb2ac | 373 | yCenter = (accPrv[0].y + accPrv[1].y + accPrv[2].y + accPrv[3].y + accPrv[4].y)/5.0; |
mjr | 1:d913e0afb2ac | 374 | } |
mjr | 1:d913e0afb2ac | 375 | |
mjr | 1:d913e0afb2ac | 376 | // reset the auto-center timer |
mjr | 1:d913e0afb2ac | 377 | acTimer.reset(); |
mjr | 1:d913e0afb2ac | 378 | t0ac = acTimer.read_ms(); |
mjr | 1:d913e0afb2ac | 379 | } |
mjr | 1:d913e0afb2ac | 380 | |
mjr | 1:d913e0afb2ac | 381 | // adjust for our auto centering |
mjr | 1:d913e0afb2ac | 382 | xa -= xCenter; |
mjr | 1:d913e0afb2ac | 383 | ya -= yCenter; |
mjr | 1:d913e0afb2ac | 384 | |
mjr | 1:d913e0afb2ac | 385 | // confine to the unit interval |
mjr | 1:d913e0afb2ac | 386 | if (xa < -1.0) xa = -1.0; |
mjr | 1:d913e0afb2ac | 387 | if (xa > 1.0) xa = 1.0; |
mjr | 1:d913e0afb2ac | 388 | if (ya < -1.0) ya = -1.0; |
mjr | 1:d913e0afb2ac | 389 | if (ya > 1.0) ya = 1.0; |
mjr | 0:5acbbe3f4cf4 | 390 | |
mjr | 1:d913e0afb2ac | 391 | // figure the new mouse report data |
mjr | 1:d913e0afb2ac | 392 | int xnew = (int)(127 * xa); |
mjr | 1:d913e0afb2ac | 393 | int ynew = (int)(127 * ya); |
mjr | 1:d913e0afb2ac | 394 | |
mjr | 1:d913e0afb2ac | 395 | // send an update if the position has changed |
mjr | 1:d913e0afb2ac | 396 | // if (xnew != x || ynew != y || znew != z) |
mjr | 0:5acbbe3f4cf4 | 397 | { |
mjr | 1:d913e0afb2ac | 398 | x = xnew; |
mjr | 1:d913e0afb2ac | 399 | y = ynew; |
mjr | 1:d913e0afb2ac | 400 | z = znew; |
mjr | 1:d913e0afb2ac | 401 | |
mjr | 1:d913e0afb2ac | 402 | // Send the status report. Note that the X axis needs to be |
mjr | 1:d913e0afb2ac | 403 | // reversed, becasue the native accelerometer reports seem to |
mjr | 1:d913e0afb2ac | 404 | // assume that the card is component side down. |
mjr | 1:d913e0afb2ac | 405 | js.update(x, -y, z, 0); |
mjr | 0:5acbbe3f4cf4 | 406 | } |
mjr | 1:d913e0afb2ac | 407 | |
mjr | 1:d913e0afb2ac | 408 | // show a heartbeat flash in blue every so often |
mjr | 1:d913e0afb2ac | 409 | if (hbTimer.read_ms() - t0Hb > 1000) |
mjr | 1:d913e0afb2ac | 410 | { |
mjr | 1:d913e0afb2ac | 411 | // invert the blue LED state |
mjr | 1:d913e0afb2ac | 412 | hb = !hb; |
mjr | 1:d913e0afb2ac | 413 | led3 = (hb ? .5 : 1); |
mjr | 1:d913e0afb2ac | 414 | |
mjr | 1:d913e0afb2ac | 415 | // reset the heartbeat timer |
mjr | 1:d913e0afb2ac | 416 | hbTimer.reset(); |
mjr | 1:d913e0afb2ac | 417 | t0Hb = hbTimer.read_ms(); |
mjr | 1:d913e0afb2ac | 418 | } |
mjr | 1:d913e0afb2ac | 419 | } |
mjr | 0:5acbbe3f4cf4 | 420 | } |