Home | History | Annotate | Download | only in gesture_test
      1 /**
      2  *  Gesture Test application for Invensense's MPU6/9xxx (w/ DMP).
      3  */
      4 
      5 #include <unistd.h>
      6 #include <dirent.h>
      7 #include <fcntl.h>
      8 #include <stdio.h>
      9 #include <errno.h>
     10 #include <sys/stat.h>
     11 #include <stdlib.h>
     12 #include <features.h>
     13 #include <dirent.h>
     14 #include <string.h>
     15 #include <poll.h>
     16 #include <stddef.h>
     17 #include <linux/input.h>
     18 #include <time.h>
     19 #include <linux/time.h>
     20 #include <unistd.h>
     21 #include <termios.h>
     22 
     23 #include "invensense.h"
     24 #include "ml_math_func.h"
     25 #include "storage_manager.h"
     26 #include "ml_stored_data.h"
     27 #include "ml_sysfs_helper.h"
     28 #include "mlos.h"
     29 
     30 //#define DEBUG_PRINT   /* Uncomment to print Gyro & Accel read from Driver */
     31 
     32 #define SUPPORT_SCREEN_ORIENTATION
     33 //#define SUPPORT_TAP
     34 //#define SUPPORT_ORIENTATION
     35 #define SUPPORT_PEDOMETER
     36 #define SUPPORT_SMD
     37 
     38 #define MAX_SYSFS_NAME_LEN  (100)
     39 #define MAX_SYSFS_ATTRB     (sizeof(struct sysfs_attrbs) / sizeof(char*))
     40 #define IIO_SYSFS_PATH      "/sys/bus/iio/devices/iio:device0"
     41 #define IIO_HUB_NAME        "inv_hub"
     42 
     43 #define POLL_TIME           (2000) // 2sec
     44 
     45 struct sysfs_attrbs {
     46     char *name;
     47     char *enable;
     48     char *power_state;
     49     char *dmp_on;
     50     char *dmp_int_on;
     51     char *dmp_firmware;
     52     char *firmware_loaded;
     53 #ifdef SUPPORT_SCREEN_ORIENTATION
     54     char *event_display_orientation;
     55     char *display_orientation_on;
     56 #endif
     57 #ifdef SUPPORT_ORIENTATION
     58     char *event_orientation;
     59     char *orientation_on;
     60 #endif
     61 #ifdef SUPPORT_TAP
     62     char *event_tap;
     63     char *tap_min_count;
     64     char *tap_on;
     65     char *tap_threshold;
     66     char *tap_time;
     67 #endif
     68 #ifdef SUPPORT_PEDOMETER
     69     char *pedometer_on;
     70     char *pedometer_steps;
     71     char *pedometer_time;
     72 #endif
     73 #ifdef SUPPORT_SMD
     74     char *event_smd;
     75     char *smd_enable;
     76     char *smd_threshold;
     77     char *smd_delay_threshold;
     78     char *smd_delay_threshold2;
     79 #endif
     80 } mpu;
     81 
     82 enum {
     83 #ifdef SUPPORT_TAP
     84     FEAT_TAP,
     85 #endif
     86 #ifdef SUPPORT_SCREEN_ORIENTATION
     87     FEAT_SCREEN_ORIENTATION,
     88 #endif
     89 #ifdef SUPPORT_ORIENTATION
     90     FEAT_ORIENTATION,
     91 #endif
     92 #ifdef SUPPORT_PEDOMETER
     93     FEAT_PEDOMETER,
     94 #endif
     95 #ifdef SUPPORT_SMD
     96     FEAT_SMD,
     97 #endif
     98 
     99     NUM_DMP_FEATS
    100 };
    101 
    102 char *sysfs_names_ptr;
    103 #ifdef SUPPORT_PEDOMETER
    104 unsigned long last_pedometer_poll = 0L;
    105 unsigned long pedometer_poll_timeout = 500L; // .5 second
    106 #endif
    107 struct pollfd pfd[NUM_DMP_FEATS];
    108 bool android_hub = false;   // flag to indicate true=Hub, false=non-hub
    109 
    110 /*******************************************************************************
    111  *                       DMP Feature Supported Functions
    112  ******************************************************************************/
    113 
    114 int read_sysfs_int(char *filename, int *var)
    115 {
    116     int res=0;
    117     FILE *fp;
    118 
    119     fp = fopen(filename, "r");
    120     if (fp!=NULL) {
    121         fscanf(fp, "%d\n", var);
    122         fclose(fp);
    123     } else {
    124         printf("ERR open file to read: %s\n", filename);
    125         res= -1;
    126     }
    127     return res;
    128 }
    129 
    130 int write_sysfs_int(char *filename, int data)
    131 {
    132     int res=0;
    133     FILE  *fp;
    134 
    135 #ifdef DEBUG_PRINT
    136     printf("writing '%s' with '%d'\n", filename, data);
    137 #endif
    138 
    139     fp = fopen(filename, "w");
    140     if (fp != NULL) {
    141         fprintf(fp, "%d\n", data);
    142         fclose(fp);
    143     } else {
    144         printf("ERR open file to write: %s\n", filename);
    145         res = -1;
    146     }
    147     return res;
    148 }
    149 
    150 /**************************************************
    151     This _kbhit() function is courtesy of the web
    152 ***************************************************/
    153 int _kbhit(void)
    154 {
    155     static const int STDIN = 0;
    156     static bool initialized = false;
    157 
    158     if (! initialized) {
    159         // Use termios to turn off line buffering
    160         struct termios term;
    161         tcgetattr(STDIN, &term);
    162         term.c_lflag &= ~ICANON;
    163         tcsetattr(STDIN, TCSANOW, &term);
    164         setbuf(stdin, NULL);
    165         initialized = true;
    166     }
    167 
    168     int bytesWaiting;
    169     ioctl(STDIN, FIONREAD, &bytesWaiting);
    170     return bytesWaiting;
    171 }
    172 
    173 int inv_init_sysfs_attributes(void)
    174 {
    175     unsigned char i = 0;
    176     char sysfs_path[MAX_SYSFS_NAME_LEN];
    177     char *sptr;
    178     char **dptr;
    179 
    180     sysfs_names_ptr =
    181             (char*)malloc(sizeof(char[MAX_SYSFS_ATTRB][MAX_SYSFS_NAME_LEN]));
    182     sptr = sysfs_names_ptr;
    183     if (sptr != NULL) {
    184         dptr = (char**)&mpu;
    185         do {
    186             *dptr++ = sptr;
    187             sptr += sizeof(char[MAX_SYSFS_NAME_LEN]);
    188         } while (++i < MAX_SYSFS_ATTRB);
    189     } else {
    190         printf("couldn't alloc mem for sysfs paths\n");
    191         return -1;
    192     }
    193 
    194     // get proper (in absolute/relative) IIO path & build MPU's sysfs paths
    195     inv_get_sysfs_path(sysfs_path);
    196 
    197     sprintf(mpu.name, "%s%s", sysfs_path, "/name");
    198     sprintf(mpu.enable, "%s%s", sysfs_path, "/buffer/enable");
    199     sprintf(mpu.power_state, "%s%s", sysfs_path, "/power_state");
    200     sprintf(mpu.dmp_on,"%s%s", sysfs_path, "/dmp_on");
    201     sprintf(mpu.dmp_int_on, "%s%s", sysfs_path, "/dmp_int_on");
    202     sprintf(mpu.dmp_firmware, "%s%s", sysfs_path, "/dmp_firmware");
    203     sprintf(mpu.firmware_loaded, "%s%s", sysfs_path, "/firmware_loaded");
    204 
    205 #ifdef SUPPORT_SCREEN_ORIENTATION
    206     sprintf(mpu.event_display_orientation, "%s%s",
    207             sysfs_path, "/event_display_orientation");
    208     sprintf(mpu.display_orientation_on, "%s%s",
    209             sysfs_path, "/display_orientation_on");
    210 #endif
    211 #ifdef SUPPORT_ORIENTATION
    212     sprintf(mpu.event_orientation, "%s%s", sysfs_path, "/event_orientation");
    213     sprintf(mpu.orientation_on, "%s%s", sysfs_path, "/orientation_on");
    214 #endif
    215 #ifdef SUPPORT_TAP
    216     sprintf(mpu.event_tap, "%s%s", sysfs_path, "/event_tap");
    217     sprintf(mpu.tap_min_count, "%s%s", sysfs_path, "/tap_min_count");
    218     sprintf(mpu.tap_on, "%s%s", sysfs_path, "/tap_on");
    219     sprintf(mpu.tap_threshold, "%s%s", sysfs_path, "/tap_threshold");
    220     sprintf(mpu.tap_time, "%s%s", sysfs_path, "/tap_time");
    221 #endif
    222 #ifdef SUPPORT_PEDOMETER
    223     sprintf(mpu.pedometer_on, "%s%s", sysfs_path, "/dmp_on");
    224     sprintf(mpu.pedometer_steps, "%s%s", sysfs_path, "/pedometer_steps");
    225     sprintf(mpu.pedometer_time, "%s%s", sysfs_path, "/pedometer_time");
    226 #endif
    227 #ifdef SUPPORT_SMD
    228     sprintf(mpu.event_smd, "%s%s", sysfs_path, "/event_smd");
    229     sprintf(mpu.smd_enable, "%s%s", sysfs_path, "/smd_enable");
    230     sprintf(mpu.smd_threshold, "%s%s", sysfs_path, "/smd_threshold");
    231     sprintf(mpu.smd_delay_threshold, "%s%s",
    232             sysfs_path, "/smd_delay_threshold");
    233     sprintf(mpu.smd_delay_threshold2, "%s%s",
    234             sysfs_path, "/smd_delay_threshold2");
    235 #endif
    236 
    237 #if 0
    238     // test print sysfs paths
    239     dptr = (char**)&mpu;
    240     for (i = 0; i < MAX_SYSFS_ATTRB; i++) {
    241         MPL_LOGE("sysfs path: %s", *dptr++);
    242     }
    243 #endif
    244     return 0;
    245 }
    246 
    247 int dmp_fw_loaded(void)
    248 {
    249     int fw_loaded;
    250     if (read_sysfs_int(mpu.firmware_loaded, &fw_loaded) < 0)
    251         fw_loaded= 0;
    252     return fw_loaded;
    253 }
    254 
    255 int is_android_hub(void)
    256 {
    257     char dev_name[8];
    258     FILE *fp;
    259 
    260     fp= fopen(mpu.name, "r");
    261     fgets(dev_name, 8, fp);
    262     fclose(fp);
    263 
    264     if (!strncmp(dev_name, IIO_HUB_NAME, sizeof(IIO_HUB_NAME))) {
    265         android_hub = true;
    266     }else {
    267         android_hub = false;
    268     }
    269 
    270     return 0;
    271 }
    272 
    273 /*
    274     Enablers for the gestures
    275 */
    276 
    277 int master_enable(int en)
    278 {
    279     if (write_sysfs_int(mpu.enable, en) < 0) {
    280         printf("GT:ERR-can't write 'buffer/enable'");
    281         return -1;
    282     }
    283     return 0;
    284 }
    285 
    286 #ifdef SUPPORT_TAP
    287 int enable_tap(int en)
    288 {
    289     if (write_sysfs_int(mpu.tap_on, en) < 0) {
    290         printf("GT:ERR-can't write 'tap_on'\n");
    291         return -1;
    292     }
    293 
    294     return 0;
    295 }
    296 #endif
    297 
    298 /* Unnecessary: pedometer_on == dmp_on, which is always on
    299 #ifdef SUPPORT_PEDOMETER
    300 int enable_pedometer(int en)
    301 {
    302     if (write_sysfs_int(mpu.pedometer_on, en) < 0) {
    303         printf("GT:ERR-can't write 'pedometer_on'\n");
    304         return -1;
    305     }
    306 
    307     return 0;
    308 }
    309 #endif
    310 */
    311 
    312 #ifdef SUPPORT_SCREEN_ORIENTATION
    313 int enable_display_orientation(int en)
    314 {
    315     if (write_sysfs_int(mpu.display_orientation_on, en) < 0) {
    316         printf("GT:ERR-can't write 'display_orientation_on'\n");
    317         return -1;
    318     }
    319 
    320     return 0;
    321 }
    322 #endif
    323 
    324 #ifdef SUPPORT_ORIENTATION
    325 int enable_orientation(int en)
    326 {
    327     if (write_sysfs_int(mpu.orientation_on, en) < 0) {
    328         printf("GT:ERR-can't write 'orientation_on'\n");
    329         return -1;
    330     }
    331 
    332     return 0;
    333 }
    334 #endif
    335 
    336 #ifdef SUPPORT_SMD
    337 int enable_smd(int en)
    338 {
    339     if (write_sysfs_int(mpu.smd_enable, en) < 0) {
    340         printf("GT:ERR-can't write 'smd_enable'\n");
    341         return -1;
    342     }
    343     return 0;
    344 }
    345 #endif
    346 
    347 /*
    348     Handlers for the gestures
    349 */
    350 #ifdef SUPPORT_TAP
    351 int tap_handler(void)
    352 {
    353     FILE *fp;
    354     int tap, tap_dir, tap_num;
    355 
    356     fp = fopen(mpu.event_tap, "rt");
    357     fscanf(fp, "%d\n", &tap);
    358     fclose(fp);
    359 
    360     tap_dir = tap/8;
    361     tap_num = tap%8 + 1;
    362 
    363 #ifdef DEBUG_PRINT
    364     printf("GT:Tap Handler **\n");
    365     printf("Tap= %x\n", tap);
    366     printf("Tap Dir= %x\n", tap_dir);
    367     printf("Tap Num= %x\n", tap_num);
    368 #endif
    369 
    370     switch (tap_dir) {
    371         case 1:
    372             printf("Tap Axis->X Pos, ");
    373             break;
    374         case 2:
    375             printf("Tap Axis->X Neg, ");
    376             break;
    377         case 3:
    378             printf("Tap Axis->Y Pos, ");
    379             break;
    380         case 4:
    381             printf("Tap Axis->Y Neg, ");
    382             break;
    383         case 5:
    384             printf("Tap Axis->Z Pos, ");
    385             break;
    386         case 6:
    387             printf("Tap Axis->Z Neg, ");
    388             break;
    389         default:
    390             printf("Tap Axis->Unknown, ");
    391             break;
    392     }
    393     printf("#%d\n", tap_num);
    394 
    395     return 0;
    396 }
    397 #endif
    398 
    399 #ifdef SUPPORT_PEDOMETER
    400 int pedometer_handler(void)
    401 {
    402     FILE *fp;
    403     static int last_pedometer_steps = -1;
    404     static long last_pedometer_time = -1;
    405     int pedometer_steps;
    406     long pedometer_time;
    407 
    408 #ifdef DEBUG_PRINT
    409     printf("GT:Pedometer Handler\n");
    410 #endif
    411 
    412     fp = fopen(mpu.pedometer_steps, "rt");
    413     fscanf(fp, "%d\n", &pedometer_steps);
    414     fclose(fp);
    415 
    416     fp = fopen(mpu.pedometer_time, "rt");
    417     fscanf(fp, "%ld\n", &pedometer_time);
    418     fclose(fp);
    419 
    420     if (last_pedometer_steps == -1 && last_pedometer_time == -1) {
    421         printf("Pedometer Steps: %d Time: %ld ",
    422                pedometer_steps, pedometer_time);
    423         if (pedometer_steps > 10
    424                 || pedometer_time > (pedometer_poll_timeout * 2))
    425             printf("(resumed)\n");
    426         else
    427             printf("\n");
    428     } else if (last_pedometer_steps != pedometer_steps
    429                     || last_pedometer_time != pedometer_time) {
    430     printf("Pedometer Steps: %d Time: %ld\n",
    431            pedometer_steps, pedometer_time);
    432     }
    433 
    434     last_pedometer_steps = pedometer_steps;
    435     last_pedometer_time = pedometer_time;
    436 
    437     return 0;
    438 }
    439 #endif
    440 
    441 #ifdef SUPPORT_SCREEN_ORIENTATION
    442 int display_orientation_handler(void)
    443 {
    444     FILE *fp;
    445     int orient;
    446 
    447 #ifdef DEBUG_PRINT
    448     printf("GT:Screen Orient Handler\n");
    449 #endif
    450 
    451     fp = fopen(mpu.event_display_orientation, "rt");
    452     if (!fp) {
    453         printf("GT:Cannot open '%s'\n", mpu.event_display_orientation);
    454         return -1;
    455     }
    456     fscanf(fp, "%d\n", &orient);
    457     fclose(fp);
    458 
    459     printf("Screen Orient-> %d\n", orient);
    460 
    461     return 0;
    462 }
    463 #endif
    464 
    465 #ifdef SUPPORT_ORIENTATION
    466 int host_orientation_handler(void)
    467 {
    468     FILE *fp;
    469     int orient;
    470 
    471     fp = fopen(mpu.event_orientation, "rt");
    472     fscanf(fp, "%d\n", &orient);
    473     fclose(fp);
    474 
    475 #ifdef DEBUG_PRINT
    476     printf("GT:Reg Orient Handler\n");
    477 #endif
    478 
    479     if (orient & 0x01)
    480         printf("Orient->X Up\n");
    481     if (orient & 0x02)
    482         printf("Orient->X Down\n");
    483     if (orient & 0x04)
    484         printf("Orient->Y Up\n");
    485     if (orient & 0x08)
    486         printf("Orient->Y Down\n");
    487     if (orient & 0x10)
    488         printf("Orient->Z Up\n");
    489     if (orient & 0x20)
    490         printf("Orient->Z Down\n");
    491     if (orient & 0x40)
    492         printf("Orient->Flip\n");
    493 
    494     return 0;
    495 }
    496 #endif
    497 
    498 #ifdef SUPPORT_SMD
    499 int smd_handler(void)
    500 {
    501     FILE *fp;
    502     int smd;
    503 
    504     fp = fopen(mpu.event_smd, "rt");
    505     fscanf(fp, "%d\n", &smd);
    506     fclose(fp);
    507 
    508 #ifdef DEBUG_PRINT
    509     printf("GT:SMD Handler\n");
    510 #endif
    511     printf("SMD (%d)\n", smd);
    512 
    513     /* wait for the acceleration low pass filtered tail to die off -
    514        this is to prevent that the tail end of a 2nd event of above threhsold
    515        motion be considered as also the 1st event for the next SM detection */
    516     inv_sleep(1000);
    517 
    518     /* re-enable to continue the detection */
    519     master_enable(0);
    520     enable_smd(1);
    521     master_enable(1);
    522 
    523     return 0;
    524 }
    525 #endif
    526 
    527 int enable_dmp_features(int en)
    528 {
    529     int res= -1;
    530 
    531     if (android_hub || dmp_fw_loaded()) {
    532         /* Currently there's no info regarding DMP's supported features/capabilities
    533            An error in enabling features below could be an indication of the feature
    534            not supported in current loaded DMP firmware */
    535 
    536         master_enable(0);
    537 #ifdef SUPPORT_TAP
    538         enable_tap(en);
    539 #endif
    540 #ifdef SUPPORT_SCREEN_ORIENTATION
    541         enable_display_orientation(en);
    542 #endif
    543 #ifdef SUPPORT_ORIENTATION
    544         if (android_hub == false) {
    545             // Android Hub does not support 'regular' orientation feature
    546             enable_orientation(en);
    547         }
    548 #endif
    549 #ifdef SUPPORT_SMD
    550         enable_smd(en);
    551 #endif
    552         master_enable(1);
    553         res = 0;
    554 
    555     } else {
    556         printf("GT:ERR-No DMP firmware\n");
    557         res= -1;
    558     }
    559 
    560     return res;
    561 }
    562 
    563 int init_fds(void)
    564 {
    565     int i;
    566 
    567     for (i = 0; i < NUM_DMP_FEATS; i++) {
    568         switch(i) {
    569 #ifdef SUPPORT_TAP
    570         case FEAT_TAP:
    571             pfd[i].fd = open(mpu.event_tap, O_RDONLY | O_NONBLOCK);
    572             break;
    573 #endif
    574 #ifdef SUPPORT_SCREEN_ORIENTATION
    575         case FEAT_SCREEN_ORIENTATION:
    576             pfd[i].fd = open(mpu.event_display_orientation,
    577                              O_RDONLY | O_NONBLOCK);
    578             break;
    579 #endif
    580 #ifdef SUPPORT_ORIENTATION
    581         case FEAT_ORIENTATION:
    582             pfd[i].fd = open(mpu.event_orientation, O_RDONLY | O_NONBLOCK);
    583             break;
    584 #endif
    585 #ifdef SUPPORT_SMD
    586         case FEAT_SMD:
    587             pfd[i].fd = open(mpu.event_smd, O_RDONLY | O_NONBLOCK);
    588             break;
    589 #endif
    590         default:
    591             pfd[i].fd = -1;
    592         }
    593 
    594         pfd[i].events = POLLPRI|POLLERR,
    595         pfd[i].revents = 0;
    596     }
    597 
    598     return 0;
    599 }
    600 
    601 void parse_events(struct pollfd pfd[], int num_fds)
    602 {
    603     int i;
    604 
    605     for (i = 0; i < num_fds; i++) {
    606         if(pfd[i].revents != 0) {
    607             switch(i) {
    608 #ifdef SUPPORT_TAP
    609             case FEAT_TAP:
    610                 tap_handler();
    611                 break;
    612 #endif
    613 #ifdef SUPPORT_SCREEN_ORIENTATION
    614             case FEAT_SCREEN_ORIENTATION:
    615                 display_orientation_handler();
    616                 break;
    617 #endif
    618 #ifdef SUPPORT_ORIENTATION
    619             case FEAT_ORIENTATION:
    620                 host_orientation_handler();
    621                 break;
    622 #endif
    623 #ifdef SUPPORT_SMD
    624             case FEAT_SMD:
    625                 smd_handler();
    626                 break;
    627 #endif
    628             default:
    629                 printf("GT:ERR-unhandled/unrecognized gesture event");
    630                 break;
    631             }
    632             pfd[i].revents = 0;   // no need: reset anyway
    633         }
    634     }
    635 
    636 #ifdef SUPPORT_PEDOMETER
    637     {
    638         unsigned long now;
    639         // pedometer is not event based, therefore we poll using a timer every
    640         //  pedometer_poll_timeout milliseconds
    641         if ((now = inv_get_tick_count()) - last_pedometer_poll
    642                 > pedometer_poll_timeout) {
    643             pedometer_handler();
    644             last_pedometer_poll = now;
    645         }
    646     }
    647 #endif
    648 }
    649 
    650 int close_fds(void)
    651 {
    652     int i;
    653     for (i = 0; i < NUM_DMP_FEATS; i++) {
    654         if (!pfd[i].fd)
    655             close(pfd[i].fd);
    656     }
    657     return 0;
    658 }
    659 
    660 /*******************************************************************************
    661  *                       M a i n
    662  ******************************************************************************/
    663 
    664 int main(int argc, char **argv)
    665 {
    666     char data[4];
    667     int i, res= 0;
    668 
    669     printf("\n"
    670            "****************************************************************\n"
    671            "*** NOTE:                                                    ***\n"
    672            "***       the HAL must be compiled with Low power quaternion ***\n"
    673            "***           and/or DMP screen orientation support.         ***\n"
    674            "***       'At least' one of the 4 Android virtual sensors    ***\n"
    675            "***           must be enabled.                               ***\n"
    676            "***                                                          ***\n"
    677            "*** Please perform gestures to see the output.               ***\n"
    678            "*** Press any key to stop the program.                       ***\n"
    679            "****************************************************************\n"
    680            "\n");
    681 
    682     res = inv_init_sysfs_attributes();
    683     if (res) {
    684         printf("GT:ERR-Can't allocate mem\n");
    685         return -1;
    686     }
    687 
    688     /* check if Android Hub */
    689     is_android_hub();
    690 
    691     /* init Fds to poll for gesture data */
    692     init_fds();
    693 
    694     /* on Gesture/DMP supported features */
    695     if (enable_dmp_features(1) < 0) {
    696         printf("GT:ERR-Can't enable Gestures\n");
    697         return -1;
    698     }
    699 
    700     do {
    701         for (i = 0; i < NUM_DMP_FEATS; i++)
    702             read(pfd[i].fd, data, 4);
    703         poll(pfd, NUM_DMP_FEATS, POLL_TIME);
    704         parse_events(pfd, NUM_DMP_FEATS);
    705     } while (!_kbhit());
    706 
    707     /* off Gesture/DMP supported features */
    708     if (enable_dmp_features(0) < 0) {
    709         printf("GT:ERR-Can't disable Gestures\n");
    710         return -1;
    711     }
    712 
    713     /* release resources */
    714     close_fds();
    715     if (sysfs_names_ptr)
    716         free(sysfs_names_ptr);
    717 
    718     return res;
    719 }
    720 
    721