Home | History | Annotate | Download | only in nanoapp_cmd
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <android/log.h>
     18 #include <assert.h>
     19 #include <stdio.h>
     20 #include <sys/types.h>
     21 #include <sys/stat.h>
     22 #include <fcntl.h>
     23 #include <stdbool.h>
     24 #include <stdint.h>
     25 #include <unistd.h>
     26 #include <string.h>
     27 #include <stdlib.h>
     28 #include <eventnums.h>
     29 #include <sensType.h>
     30 #include <signal.h>
     31 #include <inttypes.h>
     32 #include <errno.h>
     33 
     34 #define LOG_TAG "nanoapp_cmd"
     35 #define SENSOR_RATE_ONCHANGE    0xFFFFFF01UL
     36 #define SENSOR_RATE_ONESHOT     0xFFFFFF02UL
     37 #define SENSOR_HZ(_hz)          ((uint32_t)((_hz) * 1024.0f))
     38 #define MAX_INSTALL_CNT         8
     39 #define MAX_DOWNLOAD_RETRIES    3
     40 
     41 enum ConfigCmds
     42 {
     43     CONFIG_CMD_DISABLE      = 0,
     44     CONFIG_CMD_ENABLE       = 1,
     45     CONFIG_CMD_FLUSH        = 2,
     46     CONFIG_CMD_CFG_DATA     = 3,
     47     CONFIG_CMD_CALIBRATE    = 4,
     48 };
     49 
     50 struct ConfigCmd
     51 {
     52     uint32_t evtType;
     53     uint64_t latency;
     54     uint32_t rate;
     55     uint8_t sensorType;
     56     uint8_t cmd;
     57     uint16_t flags;
     58 } __attribute__((packed));
     59 
     60 struct AppInfo
     61 {
     62     uint32_t num;
     63     uint64_t id;
     64     uint32_t version;
     65     uint32_t size;
     66 };
     67 
     68 static int setType(struct ConfigCmd *cmd, char *sensor)
     69 {
     70     if (strcmp(sensor, "accel") == 0) {
     71         cmd->sensorType = SENS_TYPE_ACCEL;
     72     } else if (strcmp(sensor, "gyro") == 0) {
     73         cmd->sensorType = SENS_TYPE_GYRO;
     74     } else if (strcmp(sensor, "mag") == 0) {
     75         cmd->sensorType = SENS_TYPE_MAG;
     76     } else if (strcmp(sensor, "uncal_gyro") == 0) {
     77         cmd->sensorType = SENS_TYPE_GYRO;
     78     } else if (strcmp(sensor, "uncal_mag") == 0) {
     79         cmd->sensorType = SENS_TYPE_MAG;
     80     } else if (strcmp(sensor, "als") == 0) {
     81         cmd->sensorType = SENS_TYPE_ALS;
     82     } else if (strcmp(sensor, "prox") == 0) {
     83         cmd->sensorType = SENS_TYPE_PROX;
     84     } else if (strcmp(sensor, "baro") == 0) {
     85         cmd->sensorType = SENS_TYPE_BARO;
     86     } else if (strcmp(sensor, "temp") == 0) {
     87         cmd->sensorType = SENS_TYPE_TEMP;
     88     } else if (strcmp(sensor, "orien") == 0) {
     89         cmd->sensorType = SENS_TYPE_ORIENTATION;
     90     } else if (strcmp(sensor, "gravity") == 0) {
     91         cmd->sensorType = SENS_TYPE_GRAVITY;
     92     } else if (strcmp(sensor, "geomag") == 0) {
     93         cmd->sensorType = SENS_TYPE_GEO_MAG_ROT_VEC;
     94     } else if (strcmp(sensor, "linear_acc") == 0) {
     95         cmd->sensorType = SENS_TYPE_LINEAR_ACCEL;
     96     } else if (strcmp(sensor, "rotation") == 0) {
     97         cmd->sensorType = SENS_TYPE_ROTATION_VECTOR;
     98     } else if (strcmp(sensor, "game") == 0) {
     99         cmd->sensorType = SENS_TYPE_GAME_ROT_VECTOR;
    100     } else if (strcmp(sensor, "win_orien") == 0) {
    101         cmd->sensorType = SENS_TYPE_WIN_ORIENTATION;
    102         cmd->rate = SENSOR_RATE_ONCHANGE;
    103     } else if (strcmp(sensor, "tilt") == 0) {
    104         cmd->sensorType = SENS_TYPE_TILT;
    105         cmd->rate = SENSOR_RATE_ONCHANGE;
    106     } else if (strcmp(sensor, "step_det") == 0) {
    107         cmd->sensorType = SENS_TYPE_STEP_DETECT;
    108         cmd->rate = SENSOR_RATE_ONCHANGE;
    109     } else if (strcmp(sensor, "step_cnt") == 0) {
    110         cmd->sensorType = SENS_TYPE_STEP_COUNT;
    111         cmd->rate = SENSOR_RATE_ONCHANGE;
    112     } else if (strcmp(sensor, "double_tap") == 0) {
    113         cmd->sensorType = SENS_TYPE_DOUBLE_TAP;
    114         cmd->rate = SENSOR_RATE_ONCHANGE;
    115     } else if (strcmp(sensor, "flat") == 0) {
    116         cmd->sensorType = SENS_TYPE_FLAT;
    117         cmd->rate = SENSOR_RATE_ONCHANGE;
    118     } else if (strcmp(sensor, "anymo") == 0) {
    119         cmd->sensorType = SENS_TYPE_ANY_MOTION;
    120         cmd->rate = SENSOR_RATE_ONCHANGE;
    121     } else if (strcmp(sensor, "nomo") == 0) {
    122         cmd->sensorType = SENS_TYPE_NO_MOTION;
    123         cmd->rate = SENSOR_RATE_ONCHANGE;
    124     } else if (strcmp(sensor, "sigmo") == 0) {
    125         cmd->sensorType = SENS_TYPE_SIG_MOTION;
    126         cmd->rate = SENSOR_RATE_ONESHOT;
    127     } else if (strcmp(sensor, "gesture") == 0) {
    128         cmd->sensorType = SENS_TYPE_GESTURE;
    129         cmd->rate = SENSOR_RATE_ONESHOT;
    130     } else if (strcmp(sensor, "hall") == 0) {
    131         cmd->sensorType = SENS_TYPE_HALL;
    132         cmd->rate = SENSOR_RATE_ONCHANGE;
    133     } else if (strcmp(sensor, "vsync") == 0) {
    134         cmd->sensorType = SENS_TYPE_VSYNC;
    135         cmd->rate = SENSOR_RATE_ONCHANGE;
    136     } else if (strcmp(sensor, "activity") == 0) {
    137         cmd->sensorType = SENS_TYPE_ACTIVITY;
    138         cmd->rate = SENSOR_RATE_ONCHANGE;
    139     } else if (strcmp(sensor, "twist") == 0) {
    140         cmd->sensorType = SENS_TYPE_DOUBLE_TWIST;
    141         cmd->rate = SENSOR_RATE_ONCHANGE;
    142     } else {
    143         return 1;
    144     }
    145 
    146     return 0;
    147 }
    148 
    149 bool drain = false;
    150 bool stop = false;
    151 char *buf;
    152 int nread, buf_size = 2048;
    153 struct AppInfo apps[32];
    154 uint8_t appCount;
    155 char appsToInstall[MAX_INSTALL_CNT][32];
    156 
    157 void sig_handle(__attribute__((unused)) int sig)
    158 {
    159     assert(sig == SIGINT);
    160     printf("Terminating...\n");
    161     stop = true;
    162 }
    163 
    164 FILE *openFile(const char *fname, const char *mode)
    165 {
    166     FILE *f = fopen(fname, mode);
    167     if (f == NULL) {
    168         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to open %s: err=%d [%s]", fname, errno, strerror(errno));
    169         printf("\nFailed to open %s: err=%d [%s]\n", fname, errno, strerror(errno));
    170     }
    171     return f;
    172 }
    173 
    174 void parseInstalledAppInfo()
    175 {
    176     FILE *fp;
    177     char *line = NULL;
    178     size_t len;
    179     ssize_t numRead;
    180 
    181     appCount = 0;
    182 
    183     fp = openFile("/sys/class/nanohub/nanohub/app_info", "r");
    184     if (!fp)
    185         return;
    186 
    187     while ((numRead = getline(&line, &len, fp)) != -1) {
    188         struct AppInfo *currApp = &apps[appCount++];
    189         sscanf(line, "app: %d id: %" PRIx64 " ver: %d size: %d\n", &currApp->num, &currApp->id, &currApp->version, &currApp->size);
    190     }
    191 
    192     fclose(fp);
    193 
    194     if (line)
    195         free(line);
    196 }
    197 
    198 struct AppInfo *findApp(uint64_t appId)
    199 {
    200     uint8_t i;
    201 
    202     for (i = 0; i < appCount; i++) {
    203         if (apps[i].id == appId) {
    204             return &apps[i];
    205         }
    206     }
    207 
    208     return NULL;
    209 }
    210 
    211 int parseConfigAppInfo()
    212 {
    213     FILE *fp;
    214     char *line = NULL;
    215     size_t len;
    216     ssize_t numRead;
    217     int installCnt;
    218 
    219     fp = openFile("/vendor/firmware/napp_list.cfg", "r");
    220     if (!fp)
    221         return -1;
    222 
    223     parseInstalledAppInfo();
    224 
    225     installCnt = 0;
    226     while (((numRead = getline(&line, &len, fp)) != -1) && (installCnt < MAX_INSTALL_CNT)) {
    227         uint64_t appId;
    228         uint32_t appVersion;
    229         struct AppInfo* installedApp;
    230 
    231         sscanf(line, "%32s %" PRIx64 " %d\n", appsToInstall[installCnt], &appId, &appVersion);
    232 
    233         installedApp = findApp(appId);
    234         if (!installedApp || (installedApp->version < appVersion)) {
    235             installCnt++;
    236         }
    237     }
    238 
    239     fclose(fp);
    240 
    241     if (line)
    242         free(line);
    243 
    244     return installCnt;
    245 }
    246 
    247 bool fileWriteData(const char *fname, const void *data, size_t size)
    248 {
    249     int fd;
    250     bool result;
    251 
    252     fd = open(fname, O_WRONLY);
    253     if (fd < 0) {
    254         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to open %s: err=%d [%s]", fname, errno, strerror(errno));
    255         printf("\nFailed to open %s: err=%d [%s]\n", fname, errno, strerror(errno));
    256         return false;
    257     }
    258 
    259     result = true;
    260     if ((size_t)write(fd, data, size) != size) {
    261         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to write to %s; err=%d [%s]", fname, errno, strerror(errno));
    262         printf("\nFailed to write %s; err=%d [%s]\n", fname, errno, strerror(errno));
    263         result = false;
    264     }
    265     close(fd);
    266 
    267     return result;
    268 }
    269 
    270 void downloadNanohub()
    271 {
    272     char c = '1';
    273 
    274     printf("Updating nanohub OS [if required]...");
    275     fflush(stdout);
    276     if (fileWriteData("/sys/class/nanohub/nanohub/download_bl", &c, sizeof(c)))
    277         printf("done\n");
    278 }
    279 
    280 void downloadApps(int updateCnt)
    281 {
    282     int i;
    283 
    284     for (i = 0; i < updateCnt; i++) {
    285         printf("Downloading \"%s.napp\"...", appsToInstall[i]);
    286         fflush(stdout);
    287         if (fileWriteData("/sys/class/nanohub/nanohub/download_app", appsToInstall[i], strlen(appsToInstall[i])))
    288             printf("done\n");
    289     }
    290 }
    291 
    292 void resetHub()
    293 {
    294     char c = '1';
    295 
    296     printf("Resetting nanohub...");
    297     fflush(stdout);
    298     if (fileWriteData("/sys/class/nanohub/nanohub/reset", &c, sizeof(c)))
    299         printf("done\n");
    300 }
    301 
    302 int main(int argc, char *argv[])
    303 {
    304     struct ConfigCmd mConfigCmd;
    305     int fd;
    306     int i;
    307 
    308     if (argc < 3 && strcmp(argv[1], "download") != 0) {
    309         printf("usage: %s <action> <sensor> <data> -d\n", argv[0]);
    310         printf("       action: config|calibrate|flush|download\n");
    311         printf("       sensor: accel|(uncal_)gyro|(uncal_)mag|als|prox|baro|temp|orien\n");
    312         printf("               gravity|geomag|linear_acc|rotation|game\n");
    313         printf("               win_orien|tilt|step_det|step_cnt|double_tap\n");
    314         printf("               flat|anymo|nomo|sigmo|gesture|hall|vsync\n");
    315         printf("               activity|twist\n");
    316         printf("       data: config: <true|false> <rate in Hz> <latency in u-sec>\n");
    317         printf("             calibrate: [N.A.]\n");
    318         printf("             flush: [N.A.]\n");
    319         printf("       -d: if specified, %s will keep draining /dev/nanohub until cancelled.\n", argv[0]);
    320 
    321         return 1;
    322     }
    323 
    324     if (strcmp(argv[1], "config") == 0) {
    325         if (argc != 6 && argc != 7) {
    326             printf("Wrong arg number\n");
    327             return 1;
    328         }
    329         if (argc == 7) {
    330             if(strcmp(argv[6], "-d") == 0) {
    331                 drain = true;
    332             } else {
    333                 printf("Last arg unsupported, ignored.\n");
    334             }
    335         }
    336         if (strcmp(argv[3], "true") == 0)
    337             mConfigCmd.cmd = CONFIG_CMD_ENABLE;
    338         else if (strcmp(argv[3], "false") == 0) {
    339             mConfigCmd.cmd = CONFIG_CMD_DISABLE;
    340         } else {
    341             printf("Unsupported data: %s For action: %s\n", argv[3], argv[1]);
    342             return 1;
    343         }
    344         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
    345         mConfigCmd.rate = SENSOR_HZ((float)atoi(argv[4]));
    346         mConfigCmd.latency = atoi(argv[5]) * 1000ull;
    347         if (setType(&mConfigCmd, argv[2])) {
    348             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
    349             return 1;
    350         }
    351     } else if (strcmp(argv[1], "calibrate") == 0) {
    352         if (argc != 3) {
    353             printf("Wrong arg number\n");
    354             return 1;
    355         }
    356         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
    357         mConfigCmd.rate = 0;
    358         mConfigCmd.latency = 0;
    359         mConfigCmd.cmd = CONFIG_CMD_CALIBRATE;
    360         if (setType(&mConfigCmd, argv[2])) {
    361             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
    362             return 1;
    363         }
    364     } else if (strcmp(argv[1], "flush") == 0) {
    365         if (argc != 3) {
    366             printf("Wrong arg number\n");
    367             return 1;
    368         }
    369         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
    370         mConfigCmd.rate = 0;
    371         mConfigCmd.latency = 0;
    372         mConfigCmd.cmd = CONFIG_CMD_FLUSH;
    373         if (setType(&mConfigCmd, argv[2])) {
    374             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
    375             return 1;
    376         }
    377     } else if (strcmp(argv[1], "download") == 0) {
    378         if (argc != 2) {
    379             printf("Wrong arg number\n");
    380             return 1;
    381         }
    382         downloadNanohub();
    383         for (i = 0; i < MAX_DOWNLOAD_RETRIES; i++) {
    384             int updateCnt = parseConfigAppInfo();
    385             if (updateCnt > 0) {
    386                 downloadApps(updateCnt);
    387                 resetHub();
    388             } else if (!updateCnt){
    389                 return 0;
    390             }
    391         }
    392 
    393         if (parseConfigAppInfo() != 0) {
    394             __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "Failed to download all apps!");
    395             printf("Failed to download all apps!\n");
    396         }
    397         return 1;
    398     } else {
    399         printf("Unsupported action: %s\n", argv[1]);
    400         return 1;
    401     }
    402 
    403     while (!fileWriteData("/dev/nanohub", &mConfigCmd, sizeof(mConfigCmd)))
    404         continue;
    405 
    406     if (drain) {
    407         signal(SIGINT, sig_handle);
    408         fd = open("/dev/nanohub", O_RDONLY);
    409         while (!stop) {
    410             (void) read(fd, buf, buf_size);
    411         }
    412         close(fd);
    413     }
    414     return 0;
    415 }
    416