1 /* 2 $License: 3 Copyright 2011 InvenSense, Inc. 4 5 Licensed under the Apache License, Version 2.0 (the "License"); 6 you may not use this file except in compliance with the License. 7 You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11 Unless required by applicable law or agreed to in writing, software 12 distributed under the License is distributed on an "AS IS" BASIS, 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 See the License for the specific language governing permissions and 15 limitations under the License. 16 $ 17 */ 18 19 /******************************************************************************* 20 * 21 * $Id: mlcontrol.c 5641 2011-06-14 02:10:02Z mcaramello $ 22 * 23 *******************************************************************************/ 24 25 /** 26 * @defgroup CONTROL 27 * @brief Motion Library - Control Engine. 28 * The Control Library processes gyroscopes, accelerometers, and 29 * compasses to provide control signals that can be used in user 30 * interfaces. 31 * These signals can be used to manipulate objects such as documents, 32 * images, cursors, menus, etc. 33 * 34 * @{ 35 * @file mlcontrol.c 36 * @brief The Control Library. 37 * 38 */ 39 40 /* ------------------ */ 41 /* - Include Files. - */ 42 /* ------------------ */ 43 44 #include "mltypes.h" 45 #include "mlinclude.h" 46 #include "mltypes.h" 47 #include "ml.h" 48 #include "mlos.h" 49 #include "mlsl.h" 50 #include "mldl.h" 51 #include "mlcontrol.h" 52 #include "dmpKey.h" 53 #include "mlstates.h" 54 #include "mlFIFO.h" 55 #include "string.h" 56 57 /* - Global Vars. - */ 58 struct control_params cntrl_params = { 59 { 60 MLCTRL_SENSITIVITY_0_DEFAULT, 61 MLCTRL_SENSITIVITY_1_DEFAULT, 62 MLCTRL_SENSITIVITY_2_DEFAULT, 63 MLCTRL_SENSITIVITY_3_DEFAULT}, // sensitivity 64 MLCTRL_FUNCTIONS_DEFAULT, // functions 65 { 66 MLCTRL_PARAMETER_ARRAY_0_DEFAULT, 67 MLCTRL_PARAMETER_ARRAY_1_DEFAULT, 68 MLCTRL_PARAMETER_ARRAY_2_DEFAULT, 69 MLCTRL_PARAMETER_ARRAY_3_DEFAULT}, // parameterArray 70 { 71 MLCTRL_PARAMETER_AXIS_0_DEFAULT, 72 MLCTRL_PARAMETER_AXIS_1_DEFAULT, 73 MLCTRL_PARAMETER_AXIS_2_DEFAULT, 74 MLCTRL_PARAMETER_AXIS_3_DEFAULT}, // parameterAxis 75 { 76 MLCTRL_GRID_THRESHOLD_0_DEFAULT, 77 MLCTRL_GRID_THRESHOLD_1_DEFAULT, 78 MLCTRL_GRID_THRESHOLD_2_DEFAULT, 79 MLCTRL_GRID_THRESHOLD_3_DEFAULT}, // gridThreshold 80 { 81 MLCTRL_GRID_MAXIMUM_0_DEFAULT, 82 MLCTRL_GRID_MAXIMUM_1_DEFAULT, 83 MLCTRL_GRID_MAXIMUM_2_DEFAULT, 84 MLCTRL_GRID_MAXIMUM_3_DEFAULT}, // gridMaximum 85 MLCTRL_GRID_CALLBACK_DEFAULT // gridCallback 86 }; 87 88 /* - Extern Vars. - */ 89 struct control_obj cntrl_obj; 90 extern const unsigned char *dmpConfig1; 91 92 /* -------------- */ 93 /* - Functions. - */ 94 /* -------------- */ 95 96 /** 97 * @brief inv_set_control_sensitivity is used to set the sensitivity for a control 98 * signal. 99 * 100 * @pre inv_dmp_open() Must be called with MLDmpDefaultOpen() or 101 * inv_open_low_power_pedometer(). 102 * 103 * @param controlSignal Indicates which control signal is being modified. 104 * Must be one of: 105 * - INV_CONTROL_1, 106 * - INV_CONTROL_2, 107 * - INV_CONTROL_3 or 108 * - INV_CONTROL_4. 109 * 110 * @param sensitivity The sensitivity of the control signal. 111 * 112 * @return error code 113 */ 114 inv_error_t inv_set_control_sensitivity(unsigned short controlSignal, 115 long sensitivity) 116 { 117 INVENSENSE_FUNC_START; 118 unsigned char regs[2]; 119 long finalSens = 0; 120 inv_error_t result; 121 122 if (inv_get_state() < INV_STATE_DMP_OPENED) 123 return INV_ERROR_SM_IMPROPER_STATE; 124 125 finalSens = sensitivity * 100; 126 if (finalSens > 16384) { 127 finalSens = 16384; 128 } 129 regs[0] = (unsigned char)(finalSens / 256); 130 regs[1] = (unsigned char)(finalSens % 256); 131 switch (controlSignal) { 132 case INV_CONTROL_1: 133 result = inv_set_mpu_memory(KEY_D_0_224, 2, regs); 134 if (result) { 135 LOG_RESULT_LOCATION(result); 136 return result; 137 } 138 cntrl_params.sensitivity[0] = (unsigned short)sensitivity; 139 break; 140 case INV_CONTROL_2: 141 result = inv_set_mpu_memory(KEY_D_0_228, 2, regs); 142 if (result) { 143 LOG_RESULT_LOCATION(result); 144 return result; 145 } 146 cntrl_params.sensitivity[1] = (unsigned short)sensitivity; 147 break; 148 case INV_CONTROL_3: 149 result = inv_set_mpu_memory(KEY_D_0_232, 2, regs); 150 if (result) { 151 LOG_RESULT_LOCATION(result); 152 return result; 153 } 154 cntrl_params.sensitivity[2] = (unsigned short)sensitivity; 155 break; 156 case INV_CONTROL_4: 157 result = inv_set_mpu_memory(KEY_D_0_236, 2, regs); 158 if (result) { 159 LOG_RESULT_LOCATION(result); 160 return result; 161 } 162 cntrl_params.sensitivity[3] = (unsigned short)sensitivity; 163 break; 164 default: 165 break; 166 } 167 if (finalSens != sensitivity * 100) { 168 return INV_ERROR_INVALID_PARAMETER; 169 } else { 170 return INV_SUCCESS; 171 } 172 } 173 174 /** 175 * @brief inv_set_control_func allows the user to choose how the sensor data will 176 * be processed in order to provide a control parameter. 177 * inv_set_control_func allows the user to choose which control functions 178 * will be incorporated in the sensor data processing. 179 * The control functions are: 180 * - INV_GRID 181 * Indicates that the user will be controlling a system that 182 * has discrete steps, such as icons, menu entries, pixels, etc. 183 * - INV_SMOOTH 184 * Indicates that noise from unintentional motion should be filtered out. 185 * - INV_DEAD_ZONE 186 * Indicates that a dead zone should be used, below which sensor 187 * data is set to zero. 188 * - INV_HYSTERESIS 189 * Indicates that, when INV_GRID is selected, hysteresis should 190 * be used to prevent the control signal from switching rapidly across 191 * elements of the grid. 192 * 193 * @pre inv_dmp_open() Must be called with MLDmpDefaultOpen() or 194 * inv_open_low_power_pedometer(). 195 * 196 * @param function Indicates what functions will be used. 197 * Can be a bitwise OR of several values. 198 * 199 * @return Zero if the command is successful; an ML error code otherwise. 200 */ 201 inv_error_t inv_set_control_func(unsigned short function) 202 { 203 INVENSENSE_FUNC_START; 204 unsigned char regs[8] = { DINA06, DINA26, 205 DINA46, DINA66, 206 DINA0E, DINA2E, 207 DINA4E, DINA6E 208 }; 209 unsigned char i; 210 inv_error_t result; 211 212 if (inv_get_state() < INV_STATE_DMP_OPENED) 213 return INV_ERROR_SM_IMPROPER_STATE; 214 215 if ((function & INV_SMOOTH) == 0) { 216 for (i = 0; i < 8; i++) { 217 regs[i] = DINA80 + 3; 218 } 219 } 220 result = inv_set_mpu_memory(KEY_CFG_4, 8, regs); 221 if (result) { 222 LOG_RESULT_LOCATION(result); 223 return result; 224 } 225 cntrl_params.functions = function; 226 result = inv_set_dead_zone(); 227 228 return result; 229 } 230 231 /** 232 * @brief inv_get_control_signal is used to get the current control signal with 233 * high precision. 234 * inv_get_control_signal is used to acquire the current data of a control signal. 235 * If INV_GRID is being used, inv_get_grid_number will probably be preferrable. 236 * 237 * @param controlSignal Indicates which control signal is being queried. 238 * Must be one of: 239 * - INV_CONTROL_1, 240 * - INV_CONTROL_2, 241 * - INV_CONTROL_3 or 242 * - INV_CONTROL_4. 243 * 244 * @param reset Indicates whether the control signal should be reset to zero. 245 * Options are INV_RESET or INV_NO_RESET 246 * @param data A pointer to the current control signal data. 247 * 248 * @return Zero if the command is successful; an ML error code otherwise. 249 */ 250 inv_error_t inv_get_control_signal(unsigned short controlSignal, 251 unsigned short reset, long *data) 252 { 253 INVENSENSE_FUNC_START; 254 255 if (inv_get_state() != INV_STATE_DMP_STARTED) 256 return INV_ERROR_SM_IMPROPER_STATE; 257 258 switch (controlSignal) { 259 case INV_CONTROL_1: 260 *data = cntrl_obj.controlInt[0]; 261 if (reset == INV_RESET) { 262 cntrl_obj.controlInt[0] = 0; 263 } 264 break; 265 case INV_CONTROL_2: 266 *data = cntrl_obj.controlInt[1]; 267 if (reset == INV_RESET) { 268 cntrl_obj.controlInt[1] = 0; 269 } 270 break; 271 case INV_CONTROL_3: 272 *data = cntrl_obj.controlInt[2]; 273 if (reset == INV_RESET) { 274 cntrl_obj.controlInt[2] = 0; 275 } 276 break; 277 case INV_CONTROL_4: 278 *data = cntrl_obj.controlInt[3]; 279 if (reset == INV_RESET) { 280 cntrl_obj.controlInt[3] = 0; 281 } 282 break; 283 default: 284 break; 285 } 286 return INV_SUCCESS; 287 } 288 289 /** 290 * @brief inv_get_grid_num is used to get the current grid location for a certain 291 * control signal. 292 * inv_get_grid_num is used to acquire the current grid location. 293 * 294 * @pre inv_dmp_open() Must be called with MLDmpDefaultOpen() or 295 * inv_open_low_power_pedometer(). 296 * 297 * @param controlSignal Indicates which control signal is being queried. 298 * Must be one of: 299 * - INV_CONTROL_1, 300 * - INV_CONTROL_2, 301 * - INV_CONTROL_3 or 302 * - INV_CONTROL_4. 303 * 304 * @param reset Indicates whether the control signal should be reset to zero. 305 * Options are INV_RESET or INV_NO_RESET 306 * @param data A pointer to the current grid number. 307 * 308 * @return Zero if the command is successful; an ML error code otherwise. 309 */ 310 311 inv_error_t inv_get_grid_num(unsigned short controlSignal, unsigned short reset, 312 long *data) 313 { 314 INVENSENSE_FUNC_START; 315 316 if (inv_get_state() != INV_STATE_DMP_STARTED) 317 return INV_ERROR_SM_IMPROPER_STATE; 318 319 switch (controlSignal) { 320 case INV_CONTROL_1: 321 *data = cntrl_obj.gridNum[0]; 322 if (reset == INV_RESET) { 323 cntrl_obj.gridNum[0] = 0; 324 } 325 break; 326 case INV_CONTROL_2: 327 *data = cntrl_obj.gridNum[1]; 328 if (reset == INV_RESET) { 329 cntrl_obj.gridNum[1] = 0; 330 } 331 break; 332 case INV_CONTROL_3: 333 *data = cntrl_obj.gridNum[2]; 334 if (reset == INV_RESET) { 335 cntrl_obj.gridNum[2] = 0; 336 } 337 break; 338 case INV_CONTROL_4: 339 *data = cntrl_obj.gridNum[3]; 340 if (reset == INV_RESET) { 341 cntrl_obj.gridNum[3] = 0; 342 } 343 break; 344 default: 345 break; 346 } 347 348 return INV_SUCCESS; 349 } 350 351 /** 352 * @brief inv_set_grid_thresh is used to set the grid size for a control signal. 353 * inv_set_grid_thresh is used to adjust the size of the grid being controlled. 354 * @param controlSignal Indicates which control signal is being modified. 355 * Must be one of: 356 * - INV_CONTROL_1, 357 * - INV_CONTROL_2, 358 * - INV_CONTROL_3 and 359 * - INV_CONTROL_4. 360 * @param threshold The threshold of the control signal at which the grid 361 * number will be incremented or decremented. 362 * @return Zero if the command is successful; an ML error code otherwise. 363 */ 364 365 inv_error_t inv_set_grid_thresh(unsigned short controlSignal, long threshold) 366 { 367 INVENSENSE_FUNC_START; 368 369 if (inv_get_state() < INV_STATE_DMP_OPENED) 370 return INV_ERROR_SM_IMPROPER_STATE; 371 372 switch (controlSignal) { 373 case INV_CONTROL_1: 374 cntrl_params.gridThreshold[0] = threshold; 375 break; 376 case INV_CONTROL_2: 377 cntrl_params.gridThreshold[1] = threshold; 378 break; 379 case INV_CONTROL_3: 380 cntrl_params.gridThreshold[2] = threshold; 381 break; 382 case INV_CONTROL_4: 383 cntrl_params.gridThreshold[3] = threshold; 384 break; 385 default: 386 return INV_ERROR_INVALID_PARAMETER; 387 break; 388 } 389 390 return INV_SUCCESS; 391 } 392 393 /** 394 * @brief inv_set_grid_max is used to set the maximum grid number for a control signal. 395 * inv_set_grid_max is used to adjust the maximum allowed grid number, above 396 * which the grid number will not be incremented. 397 * The minimum grid number is always zero. 398 * 399 * @pre inv_dmp_open() Must be called with MLDmpDefaultOpen() or 400 * inv_open_low_power_pedometer(). 401 * 402 * @param controlSignal Indicates which control signal is being modified. 403 * Must be one of: 404 * - INV_CONTROL_1, 405 * - INV_CONTROL_2, 406 * - INV_CONTROL_3 and 407 * - INV_CONTROL_4. 408 * 409 * @param maximum The maximum grid number for a control signal. 410 * @return Zero if the command is successful; an ML error code otherwise. 411 */ 412 413 inv_error_t inv_set_grid_max(unsigned short controlSignal, long maximum) 414 { 415 INVENSENSE_FUNC_START; 416 417 if (inv_get_state() != INV_STATE_DMP_OPENED) 418 return INV_ERROR_SM_IMPROPER_STATE; 419 420 switch (controlSignal) { 421 case INV_CONTROL_1: 422 cntrl_params.gridMaximum[0] = maximum; 423 break; 424 case INV_CONTROL_2: 425 cntrl_params.gridMaximum[1] = maximum; 426 break; 427 case INV_CONTROL_3: 428 cntrl_params.gridMaximum[2] = maximum; 429 break; 430 case INV_CONTROL_4: 431 cntrl_params.gridMaximum[3] = maximum; 432 break; 433 default: 434 return INV_ERROR_INVALID_PARAMETER; 435 break; 436 } 437 438 return INV_SUCCESS; 439 } 440 441 /** 442 * @brief GridCallback function pointer type, to be passed as argument of 443 * inv_set_grid_callback. 444 * 445 * @param controlSignal Indicates which control signal crossed a grid threshold. 446 * Must be one of: 447 * - INV_CONTROL_1, 448 * - INV_CONTROL_2, 449 * - INV_CONTROL_3 and 450 * - INV_CONTROL_4. 451 * 452 * @param gridNumber An array of four numbers representing the grid number for each 453 * control signal. 454 * @param gridChange An array of four numbers representing the change in grid number 455 * for each control signal. 456 **/ 457 typedef void (*fpGridCb) (unsigned short controlSignal, long *gridNum, 458 long *gridChange); 459 460 /** 461 * @brief inv_set_grid_callback is used to register a callback function that 462 * will trigger when the grid location changes. 463 * inv_set_grid_callback allows a user to define a callback function that will 464 * run when a control signal crosses a grid threshold. 465 466 * @pre inv_dmp_open() Must be called with MLDmpDefaultOpen() or 467 * inv_open_low_power_pedometer(). inv_dmp_start must <b>NOT</b> have 468 * been called. 469 * 470 * @param func A user defined callback function 471 * @return Zero if the command is successful; an ML error code otherwise. 472 **/ 473 inv_error_t inv_set_grid_callback(fpGridCb func) 474 { 475 INVENSENSE_FUNC_START; 476 477 if (inv_get_state() != INV_STATE_DMP_OPENED) 478 return INV_ERROR_SM_IMPROPER_STATE; 479 480 cntrl_params.gridCallback = func; 481 return INV_SUCCESS; 482 } 483 484 /** 485 * @brief inv_set_control_data is used to assign physical parameters to control signals. 486 * inv_set_control_data allows flexibility in assigning physical parameters to 487 * control signals. For example, the user is allowed to use raw gyroscope data 488 * as an input to the control algorithm. 489 * Alternatively, angular velocity can be used, which combines gyroscopes and 490 * accelerometers to provide a more robust physical parameter. Finally, angular 491 * velocity in world coordinates can be used, providing a control signal in 492 * which pitch and yaw are provided relative to gravity. 493 * 494 * @pre inv_dmp_open() Must be called with MLDmpDefaultOpen() or 495 * inv_open_low_power_pedometer(). 496 * 497 * @param controlSignal Indicates which control signal is being modified. 498 * Must be one of: 499 * - INV_CONTROL_1, 500 * - INV_CONTROL_2, 501 * - INV_CONTROL_3 or 502 * - INV_CONTROL_4. 503 * 504 * @param parameterArray Indicates which parameter array is being assigned to a 505 * control signal. Must be one of: 506 * - INV_GYROS, 507 * - INV_ANGULAR_VELOCITY, or 508 * 509 * @param parameterAxis Indicates which axis of the parameter array will be used. 510 * Must be: 511 * - INV_ROLL, 512 * - INV_PITCH, or 513 * - INV_YAW. 514 */ 515 516 inv_error_t inv_set_control_data(unsigned short controlSignal, 517 unsigned short parameterArray, 518 unsigned short parameterAxis) 519 { 520 INVENSENSE_FUNC_START; 521 unsigned char regs[2] = { DINA80 + 10, DINA20 }; 522 inv_error_t result; 523 524 if (inv_get_state() != INV_STATE_DMP_OPENED) 525 return INV_ERROR_SM_IMPROPER_STATE; 526 527 if (parameterArray == INV_ANGULAR_VELOCITY) { 528 regs[0] = DINA80 + 5; 529 regs[1] = DINA00; 530 } 531 switch (controlSignal) { 532 case INV_CONTROL_1: 533 cntrl_params.parameterArray[0] = parameterArray; 534 switch (parameterAxis) { 535 case INV_PITCH: 536 regs[1] += 0x02; 537 cntrl_params.parameterAxis[0] = 0; 538 break; 539 case INV_ROLL: 540 regs[1] = DINA22; 541 cntrl_params.parameterAxis[0] = 1; 542 break; 543 case INV_YAW: 544 regs[1] = DINA42; 545 cntrl_params.parameterAxis[0] = 2; 546 break; 547 default: 548 return INV_ERROR_INVALID_PARAMETER; 549 } 550 result = inv_set_mpu_memory(KEY_CFG_3, 2, regs); 551 if (result) { 552 LOG_RESULT_LOCATION(result); 553 return result; 554 } 555 break; 556 case INV_CONTROL_2: 557 cntrl_params.parameterArray[1] = parameterArray; 558 switch (parameterAxis) { 559 case INV_PITCH: 560 regs[1] += DINA0E; 561 cntrl_params.parameterAxis[1] = 0; 562 break; 563 case INV_ROLL: 564 regs[1] += DINA2E; 565 cntrl_params.parameterAxis[1] = 1; 566 break; 567 case INV_YAW: 568 regs[1] += DINA4E; 569 cntrl_params.parameterAxis[1] = 2; 570 break; 571 default: 572 return INV_ERROR_INVALID_PARAMETER; 573 } 574 result = inv_set_mpu_memory(KEY_CFG_3B, 2, regs); 575 if (result) { 576 LOG_RESULT_LOCATION(result); 577 return result; 578 } 579 break; 580 case INV_CONTROL_3: 581 cntrl_params.parameterArray[2] = parameterArray; 582 switch (parameterAxis) { 583 case INV_PITCH: 584 regs[1] += DINA0E; 585 cntrl_params.parameterAxis[2] = 0; 586 break; 587 case INV_ROLL: 588 regs[1] += DINA2E; 589 cntrl_params.parameterAxis[2] = 1; 590 break; 591 case INV_YAW: 592 regs[1] += DINA4E; 593 cntrl_params.parameterAxis[2] = 2; 594 break; 595 default: 596 return INV_ERROR_INVALID_PARAMETER; 597 } 598 result = inv_set_mpu_memory(KEY_CFG_3C, 2, regs); 599 if (result) { 600 LOG_RESULT_LOCATION(result); 601 return result; 602 } 603 break; 604 case INV_CONTROL_4: 605 cntrl_params.parameterArray[3] = parameterArray; 606 switch (parameterAxis) { 607 case INV_PITCH: 608 regs[1] += DINA0E; 609 cntrl_params.parameterAxis[3] = 0; 610 break; 611 case INV_ROLL: 612 regs[1] += DINA2E; 613 cntrl_params.parameterAxis[3] = 1; 614 break; 615 case INV_YAW: 616 regs[1] += DINA4E; 617 cntrl_params.parameterAxis[3] = 2; 618 break; 619 default: 620 return INV_ERROR_INVALID_PARAMETER; 621 } 622 result = inv_set_mpu_memory(KEY_CFG_3D, 2, regs); 623 if (result) { 624 LOG_RESULT_LOCATION(result); 625 return result; 626 } 627 break; 628 default: 629 result = INV_ERROR_INVALID_PARAMETER; 630 break; 631 } 632 return result; 633 } 634 635 /** 636 * @brief inv_get_control_data is used to get the current control data. 637 * 638 * @pre inv_dmp_open() Must be called with MLDmpDefaultOpen() or 639 * inv_open_low_power_pedometer(). 640 * 641 * @param controlSignal Indicates which control signal is being queried. 642 * Must be one of: 643 * - INV_CONTROL_1, 644 * - INV_CONTROL_2, 645 * - INV_CONTROL_3 or 646 * - INV_CONTROL_4. 647 * 648 * @param gridNum A pointer to pass gridNum info back to the user. 649 * @param gridChange A pointer to pass gridChange info back to the user. 650 * 651 * @return Zero if the command is successful; an ML error code otherwise. 652 */ 653 654 inv_error_t inv_get_control_data(long *controlSignal, long *gridNum, 655 long *gridChange) 656 { 657 INVENSENSE_FUNC_START; 658 int_fast8_t i = 0; 659 660 if (inv_get_state() != INV_STATE_DMP_STARTED) 661 return INV_ERROR_SM_IMPROPER_STATE; 662 663 for (i = 0; i < 4; i++) { 664 controlSignal[i] = cntrl_obj.controlInt[i]; 665 gridNum[i] = cntrl_obj.gridNum[i]; 666 gridChange[i] = cntrl_obj.gridChange[i]; 667 } 668 return INV_SUCCESS; 669 } 670 671 /** 672 * @internal 673 * @brief Update the ML Control engine. This function should be called 674 * every time new data from the MPU becomes available. 675 * Control engine outputs are written to the cntrl_obj data 676 * structure. 677 * @return INV_SUCCESS or an error code. 678 **/ 679 inv_error_t inv_update_control(struct inv_obj_t * inv_obj) 680 { 681 INVENSENSE_FUNC_START; 682 unsigned char i; 683 long gridTmp; 684 long tmp; 685 686 inv_get_cntrl_data(cntrl_obj.mlGridNumDMP); 687 688 for (i = 0; i < 4; i++) { 689 if (cntrl_params.functions & INV_GRID) { 690 if (cntrl_params.functions & INV_HYSTERESIS) { 691 cntrl_obj.mlGridNumDMP[i] += cntrl_obj.gridNumOffset[i]; 692 } 693 cntrl_obj.mlGridNumDMP[i] = 694 cntrl_obj.mlGridNumDMP[i] / 2 + 1073741824L; 695 cntrl_obj.controlInt[i] = 696 (cntrl_obj.mlGridNumDMP[i] % 697 (128 * cntrl_params.gridThreshold[i])) / 128; 698 gridTmp = 699 cntrl_obj.mlGridNumDMP[i] / (128 * 700 cntrl_params.gridThreshold[i]); 701 tmp = 1 + 16777216L / cntrl_params.gridThreshold[i]; 702 cntrl_obj.gridChange[i] = gridTmp - cntrl_obj.lastGridNum[i]; 703 if (cntrl_obj.gridChange[i] > tmp / 2) { 704 cntrl_obj.gridChange[i] = 705 gridTmp - tmp - cntrl_obj.lastGridNum[i]; 706 } else if (cntrl_obj.gridChange[i] < -tmp / 2) { 707 cntrl_obj.gridChange[i] = 708 gridTmp + tmp - cntrl_obj.lastGridNum[i]; 709 } 710 if ((cntrl_params.functions & INV_HYSTERESIS) 711 && (cntrl_obj.gridChange[i] != 0)) { 712 if (cntrl_obj.gridChange[i] > 0) { 713 cntrl_obj.gridNumOffset[i] += 714 128 * cntrl_params.gridThreshold[i]; 715 cntrl_obj.controlInt[i] = cntrl_params.gridThreshold[i] / 2; 716 } 717 if (cntrl_obj.gridChange[i] < 0) { 718 cntrl_obj.gridNumOffset[i] -= 719 128 * cntrl_params.gridThreshold[i]; 720 cntrl_obj.controlInt[i] = cntrl_params.gridThreshold[i] / 2; 721 } 722 } 723 cntrl_obj.gridNum[i] += cntrl_obj.gridChange[i]; 724 if (cntrl_obj.gridNum[i] >= cntrl_params.gridMaximum[i]) { 725 cntrl_obj.gridNum[i] = cntrl_params.gridMaximum[i]; 726 if (cntrl_obj.controlInt[i] >= 727 cntrl_params.gridThreshold[i] / 2) { 728 cntrl_obj.controlInt[i] = cntrl_params.gridThreshold[i] / 2; 729 } 730 } else if (cntrl_obj.gridNum[i] <= 0) { 731 cntrl_obj.gridNum[i] = 0; 732 if (cntrl_obj.controlInt[i] < cntrl_params.gridThreshold[i] / 2) { 733 cntrl_obj.controlInt[i] = cntrl_params.gridThreshold[i] / 2; 734 } 735 } 736 cntrl_obj.lastGridNum[i] = gridTmp; 737 if ((cntrl_params.gridCallback) && (cntrl_obj.gridChange[i] != 0)) { 738 cntrl_params.gridCallback((INV_CONTROL_1 << i), 739 cntrl_obj.gridNum, 740 cntrl_obj.gridChange); 741 } 742 743 } else { 744 cntrl_obj.controlInt[i] = cntrl_obj.mlGridNumDMP[i]; 745 } 746 747 } 748 749 return INV_SUCCESS; 750 } 751 752 /** 753 * @brief Enables the INV_CONTROL engine. 754 * 755 * @note This function replaces MLEnable(INV_CONTROL) 756 * 757 * @pre inv_dmp_open() with MLDmpDefaultOpen or MLDmpPedometerStandAlone() must 758 * have been called. 759 * 760 * @return INV_SUCCESS or non-zero error code 761 */ 762 inv_error_t inv_enable_control(void) 763 { 764 INVENSENSE_FUNC_START; 765 766 if (inv_get_state() != INV_STATE_DMP_OPENED) 767 return INV_ERROR_SM_IMPROPER_STATE; 768 769 memset(&cntrl_obj, 0, sizeof(cntrl_obj)); 770 771 inv_register_fifo_rate_process(inv_update_control, INV_PRIORITY_CONTROL); // fixme, someone needs to send control data to the fifo 772 return INV_SUCCESS; 773 } 774 775 /** 776 * @brief Disables the INV_CONTROL engine. 777 * 778 * @note This function replaces MLDisable(INV_CONTROL) 779 * 780 * @pre inv_dmp_open() with MLDmpDefaultOpen or MLDmpPedometerStandAlone() must 781 * have been called. 782 * 783 * @return INV_SUCCESS or non-zero error code 784 */ 785 inv_error_t inv_disable_control(void) 786 { 787 INVENSENSE_FUNC_START; 788 789 if (inv_get_state() < INV_STATE_DMP_STARTED) 790 return INV_ERROR_SM_IMPROPER_STATE; 791 792 return INV_SUCCESS; 793 } 794 795 /** 796 * @} 797 */ 798