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 #define LOG_TAG "nanoapp_cmd"
     18 
     19 #include <assert.h>
     20 #include <errno.h>
     21 #include <fcntl.h>
     22 #include <inttypes.h>
     23 #include <signal.h>
     24 #include <stdbool.h>
     25 #include <stdint.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <sys/stat.h>
     29 #include <sys/types.h>
     30 #include <string.h>
     31 #include <unistd.h>
     32 
     33 #include <android/log.h>
     34 
     35 #include <nanohub/nanohub.h>
     36 #include <eventnums.h>
     37 #include <sensType.h>
     38 
     39 #define SENSOR_RATE_ONCHANGE    0xFFFFFF01UL
     40 #define SENSOR_RATE_ONESHOT     0xFFFFFF02UL
     41 #define SENSOR_HZ(_hz)          ((uint32_t)((_hz) * 1024.0f))
     42 #define MAX_APP_NAME_LEN        32
     43 #define MAX_INSTALL_CNT         8
     44 #define MAX_UNINSTALL_CNT       8
     45 #define MAX_DOWNLOAD_RETRIES    4
     46 #define UNINSTALL_CMD           "uninstall"
     47 
     48 #define NANOHUB_EXT_APP_DELETE  2
     49 
     50 #define LOGE(fmt, ...) do { \
     51         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__); \
     52         printf(fmt "\n", ##__VA_ARGS__); \
     53     } while (0)
     54 
     55 enum ConfigCmds
     56 {
     57     CONFIG_CMD_DISABLE      = 0,
     58     CONFIG_CMD_ENABLE       = 1,
     59     CONFIG_CMD_FLUSH        = 2,
     60     CONFIG_CMD_CFG_DATA     = 3,
     61     CONFIG_CMD_CALIBRATE    = 4,
     62 };
     63 
     64 struct ConfigCmd
     65 {
     66     uint32_t evtType;
     67     uint64_t latency;
     68     uint32_t rate;
     69     uint8_t sensorType;
     70     uint8_t cmd;
     71     uint16_t flags;
     72 } __attribute__((packed));
     73 
     74 struct App
     75 {
     76     uint32_t num;
     77     uint64_t id;
     78     uint32_t version;
     79     uint32_t size;
     80 };
     81 
     82 static int setType(struct ConfigCmd *cmd, char *sensor)
     83 {
     84     if (strcmp(sensor, "accel") == 0) {
     85         cmd->sensorType = SENS_TYPE_ACCEL;
     86     } else if (strcmp(sensor, "gyro") == 0) {
     87         cmd->sensorType = SENS_TYPE_GYRO;
     88     } else if (strcmp(sensor, "mag") == 0) {
     89         cmd->sensorType = SENS_TYPE_MAG;
     90     } else if (strcmp(sensor, "uncal_gyro") == 0) {
     91         cmd->sensorType = SENS_TYPE_GYRO;
     92     } else if (strcmp(sensor, "uncal_mag") == 0) {
     93         cmd->sensorType = SENS_TYPE_MAG;
     94     } else if (strcmp(sensor, "als") == 0) {
     95         cmd->sensorType = SENS_TYPE_ALS;
     96     } else if (strcmp(sensor, "prox") == 0) {
     97         cmd->sensorType = SENS_TYPE_PROX;
     98     } else if (strcmp(sensor, "baro") == 0) {
     99         cmd->sensorType = SENS_TYPE_BARO;
    100     } else if (strcmp(sensor, "temp") == 0) {
    101         cmd->sensorType = SENS_TYPE_TEMP;
    102     } else if (strcmp(sensor, "orien") == 0) {
    103         cmd->sensorType = SENS_TYPE_ORIENTATION;
    104     } else if (strcmp(sensor, "gravity") == 0) {
    105         cmd->sensorType = SENS_TYPE_GRAVITY;
    106     } else if (strcmp(sensor, "geomag") == 0) {
    107         cmd->sensorType = SENS_TYPE_GEO_MAG_ROT_VEC;
    108     } else if (strcmp(sensor, "linear_acc") == 0) {
    109         cmd->sensorType = SENS_TYPE_LINEAR_ACCEL;
    110     } else if (strcmp(sensor, "rotation") == 0) {
    111         cmd->sensorType = SENS_TYPE_ROTATION_VECTOR;
    112     } else if (strcmp(sensor, "game") == 0) {
    113         cmd->sensorType = SENS_TYPE_GAME_ROT_VECTOR;
    114     } else if (strcmp(sensor, "win_orien") == 0) {
    115         cmd->sensorType = SENS_TYPE_WIN_ORIENTATION;
    116         cmd->rate = SENSOR_RATE_ONCHANGE;
    117     } else if (strcmp(sensor, "tilt") == 0) {
    118         cmd->sensorType = SENS_TYPE_TILT;
    119         cmd->rate = SENSOR_RATE_ONCHANGE;
    120     } else if (strcmp(sensor, "step_det") == 0) {
    121         cmd->sensorType = SENS_TYPE_STEP_DETECT;
    122         cmd->rate = SENSOR_RATE_ONCHANGE;
    123     } else if (strcmp(sensor, "step_cnt") == 0) {
    124         cmd->sensorType = SENS_TYPE_STEP_COUNT;
    125         cmd->rate = SENSOR_RATE_ONCHANGE;
    126     } else if (strcmp(sensor, "double_tap") == 0) {
    127         cmd->sensorType = SENS_TYPE_DOUBLE_TAP;
    128         cmd->rate = SENSOR_RATE_ONCHANGE;
    129     } else if (strcmp(sensor, "flat") == 0) {
    130         cmd->sensorType = SENS_TYPE_FLAT;
    131         cmd->rate = SENSOR_RATE_ONCHANGE;
    132     } else if (strcmp(sensor, "anymo") == 0) {
    133         cmd->sensorType = SENS_TYPE_ANY_MOTION;
    134         cmd->rate = SENSOR_RATE_ONCHANGE;
    135     } else if (strcmp(sensor, "nomo") == 0) {
    136         cmd->sensorType = SENS_TYPE_NO_MOTION;
    137         cmd->rate = SENSOR_RATE_ONCHANGE;
    138     } else if (strcmp(sensor, "sigmo") == 0) {
    139         cmd->sensorType = SENS_TYPE_SIG_MOTION;
    140         cmd->rate = SENSOR_RATE_ONESHOT;
    141     } else if (strcmp(sensor, "gesture") == 0) {
    142         cmd->sensorType = SENS_TYPE_GESTURE;
    143         cmd->rate = SENSOR_RATE_ONESHOT;
    144     } else if (strcmp(sensor, "hall") == 0) {
    145         cmd->sensorType = SENS_TYPE_HALL;
    146         cmd->rate = SENSOR_RATE_ONCHANGE;
    147     } else if (strcmp(sensor, "vsync") == 0) {
    148         cmd->sensorType = SENS_TYPE_VSYNC;
    149         cmd->rate = SENSOR_RATE_ONCHANGE;
    150     } else if (strcmp(sensor, "activity") == 0) {
    151         cmd->sensorType = SENS_TYPE_ACTIVITY;
    152         cmd->rate = SENSOR_RATE_ONCHANGE;
    153     } else if (strcmp(sensor, "twist") == 0) {
    154         cmd->sensorType = SENS_TYPE_DOUBLE_TWIST;
    155         cmd->rate = SENSOR_RATE_ONCHANGE;
    156     } else {
    157         return 1;
    158     }
    159 
    160     return 0;
    161 }
    162 
    163 bool drain = false;
    164 bool stop = false;
    165 char *buf;
    166 int nread, buf_size = 2048;
    167 struct App apps[32];
    168 uint8_t appCount;
    169 char appsToInstall[MAX_INSTALL_CNT][MAX_APP_NAME_LEN+1];
    170 uint64_t appsToUninstall[MAX_UNINSTALL_CNT];
    171 
    172 void sig_handle(__attribute__((unused)) int sig)
    173 {
    174     assert(sig == SIGINT);
    175     printf("Terminating...\n");
    176     stop = true;
    177 }
    178 
    179 FILE *openFile(const char *fname, const char *mode)
    180 {
    181     FILE *f = fopen(fname, mode);
    182     if (f == NULL) {
    183         LOGE("Failed to open %s: err=%d [%s]", fname, errno, strerror(errno));
    184     }
    185     return f;
    186 }
    187 
    188 void parseInstalledAppInfo()
    189 {
    190     FILE *fp;
    191     char *line = NULL;
    192     size_t len;
    193     ssize_t numRead;
    194 
    195     appCount = 0;
    196 
    197     fp = openFile("/sys/class/nanohub/nanohub/app_info", "r");
    198     if (!fp)
    199         return;
    200 
    201     while ((numRead = getline(&line, &len, fp)) != -1) {
    202         struct App *currApp = &apps[appCount++];
    203         sscanf(line, "app: %d id: %" PRIx64 " ver: %" PRIx32 " size: %" PRIx32 "\n", &currApp->num, &currApp->id, &currApp->version, &currApp->size);
    204     }
    205 
    206     fclose(fp);
    207 
    208     if (line)
    209         free(line);
    210 }
    211 
    212 struct App *findApp(uint64_t appId)
    213 {
    214     uint8_t i;
    215 
    216     for (i = 0; i < appCount; i++) {
    217         if (apps[i].id == appId) {
    218             return &apps[i];
    219         }
    220     }
    221 
    222     return NULL;
    223 }
    224 
    225 int parseConfigAppInfo(int *installCnt, int *uninstallCnt)
    226 {
    227     FILE *fp;
    228     char *line = NULL;
    229     size_t len;
    230     ssize_t numRead;
    231 
    232     fp = openFile("/vendor/firmware/napp_list.cfg", "r");
    233     if (!fp)
    234         return -1;
    235 
    236     parseInstalledAppInfo();
    237 
    238     *installCnt = *uninstallCnt = 0;
    239     while (((numRead = getline(&line, &len, fp)) != -1) && (*installCnt < MAX_INSTALL_CNT) && (*uninstallCnt < MAX_UNINSTALL_CNT)) {
    240         uint64_t appId;
    241         uint32_t appVersion;
    242         struct App *installedApp;
    243 
    244         sscanf(line, "%" STRINGIFY(MAX_APP_NAME_LEN) "s %" PRIx64 " %" PRIx32 "\n", appsToInstall[*installCnt], &appId, &appVersion);
    245 
    246         installedApp = findApp(appId);
    247         if (strncmp(appsToInstall[*installCnt], UNINSTALL_CMD, MAX_APP_NAME_LEN) == 0) {
    248             if (installedApp) {
    249                 appsToUninstall[*uninstallCnt] = appId;
    250                 (*uninstallCnt)++;
    251             }
    252         } else if (!installedApp || (installedApp->version < appVersion)) {
    253             (*installCnt)++;
    254         }
    255     }
    256 
    257     fclose(fp);
    258 
    259     if (line)
    260         free(line);
    261 
    262     return *installCnt + *uninstallCnt;
    263 }
    264 
    265 bool fileWriteData(const char *fname, const void *data, size_t size)
    266 {
    267     int fd;
    268     bool result;
    269 
    270     fd = open(fname, O_WRONLY);
    271     if (fd < 0) {
    272         LOGE("Failed to open %s: err=%d [%s]", fname, errno, strerror(errno));
    273         return false;
    274     }
    275 
    276     result = true;
    277     if ((size_t)write(fd, data, size) != size) {
    278         LOGE("Failed to write to %s; err=%d [%s]", fname, errno, strerror(errno));
    279         result = false;
    280     }
    281     close(fd);
    282 
    283     return result;
    284 }
    285 
    286 void downloadNanohub()
    287 {
    288     char c = '1';
    289 
    290     printf("Updating nanohub OS [if required]...");
    291     fflush(stdout);
    292     if (fileWriteData("/sys/class/nanohub/nanohub/download_bl", &c, sizeof(c)))
    293         printf("done\n");
    294 }
    295 
    296 void removeApps(int updateCnt)
    297 {
    298     uint8_t buffer[sizeof(struct HostMsgHdr) + 1 + sizeof(uint64_t)];
    299     struct HostMsgHdr *mHostMsgHdr = (struct HostMsgHdr *)(&buffer[0]);
    300     uint8_t *cmd = (uint8_t *)(&buffer[sizeof(struct HostMsgHdr)]);
    301     uint64_t *appId = (uint64_t *)(&buffer[sizeof(struct HostMsgHdr) + 1]);
    302     int i;
    303 
    304     for (i = 0; i < updateCnt; i++) {
    305         mHostMsgHdr->eventId = EVT_APP_FROM_HOST;
    306         mHostMsgHdr->appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
    307         mHostMsgHdr->len = 1 + sizeof(uint64_t);
    308         *cmd = NANOHUB_EXT_APP_DELETE;
    309         memcpy(appId, &appsToUninstall[i], sizeof(uint64_t));
    310         printf("Deleting \"%016" PRIx64 "\"...", appsToUninstall[i]);
    311         fflush(stdout);
    312         if (fileWriteData("/dev/nanohub", buffer, sizeof(buffer)))
    313             printf("done\n");
    314     }
    315 }
    316 
    317 void downloadApps(int updateCnt)
    318 {
    319     int i;
    320 
    321     for (i = 0; i < updateCnt; i++) {
    322         printf("Downloading \"%s.napp\"...", appsToInstall[i]);
    323         fflush(stdout);
    324         if (fileWriteData("/sys/class/nanohub/nanohub/download_app", appsToInstall[i], strlen(appsToInstall[i])))
    325             printf("done\n");
    326     }
    327 }
    328 
    329 void eraseSharedArea()
    330 {
    331     char c = '1';
    332 
    333     printf("Erasing entire nanohub shared area...");
    334     fflush(stdout);
    335     if (fileWriteData("/sys/class/nanohub/nanohub/erase_shared", &c, sizeof(c)))
    336         printf("done\n");
    337 }
    338 
    339 void resetHub()
    340 {
    341     char c = '1';
    342 
    343     printf("Resetting nanohub...");
    344     fflush(stdout);
    345     if (fileWriteData("/sys/class/nanohub/nanohub/reset", &c, sizeof(c)))
    346         printf("done\n");
    347 }
    348 
    349 int main(int argc, char *argv[])
    350 {
    351     struct ConfigCmd mConfigCmd;
    352     int fd;
    353     int i;
    354 
    355     if (argc < 3 && (argc < 2 || strcmp(argv[1], "download") != 0)) {
    356         printf("usage: %s <action> <sensor> <data> -d\n", argv[0]);
    357         printf("       action: config|calibrate|flush|download\n");
    358         printf("       sensor: accel|(uncal_)gyro|(uncal_)mag|als|prox|baro|temp|orien\n");
    359         printf("               gravity|geomag|linear_acc|rotation|game\n");
    360         printf("               win_orien|tilt|step_det|step_cnt|double_tap\n");
    361         printf("               flat|anymo|nomo|sigmo|gesture|hall|vsync\n");
    362         printf("               activity|twist\n");
    363         printf("       data: config: <true|false> <rate in Hz> <latency in u-sec>\n");
    364         printf("             calibrate: [N.A.]\n");
    365         printf("             flush: [N.A.]\n");
    366         printf("       -d: if specified, %s will keep draining /dev/nanohub until cancelled.\n", argv[0]);
    367 
    368         return 1;
    369     }
    370 
    371     if (strcmp(argv[1], "config") == 0) {
    372         if (argc != 6 && argc != 7) {
    373             printf("Wrong arg number\n");
    374             return 1;
    375         }
    376         if (argc == 7) {
    377             if(strcmp(argv[6], "-d") == 0) {
    378                 drain = true;
    379             } else {
    380                 printf("Last arg unsupported, ignored.\n");
    381             }
    382         }
    383         if (strcmp(argv[3], "true") == 0)
    384             mConfigCmd.cmd = CONFIG_CMD_ENABLE;
    385         else if (strcmp(argv[3], "false") == 0) {
    386             mConfigCmd.cmd = CONFIG_CMD_DISABLE;
    387         } else {
    388             printf("Unsupported data: %s For action: %s\n", argv[3], argv[1]);
    389             return 1;
    390         }
    391         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
    392         mConfigCmd.rate = SENSOR_HZ((float)atoi(argv[4]));
    393         mConfigCmd.latency = atoi(argv[5]) * 1000ull;
    394         if (setType(&mConfigCmd, argv[2])) {
    395             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
    396             return 1;
    397         }
    398     } else if (strcmp(argv[1], "calibrate") == 0) {
    399         if (argc != 3) {
    400             printf("Wrong arg number\n");
    401             return 1;
    402         }
    403         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
    404         mConfigCmd.rate = 0;
    405         mConfigCmd.latency = 0;
    406         mConfigCmd.cmd = CONFIG_CMD_CALIBRATE;
    407         if (setType(&mConfigCmd, argv[2])) {
    408             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
    409             return 1;
    410         }
    411     } else if (strcmp(argv[1], "flush") == 0) {
    412         if (argc != 3) {
    413             printf("Wrong arg number\n");
    414             return 1;
    415         }
    416         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
    417         mConfigCmd.rate = 0;
    418         mConfigCmd.latency = 0;
    419         mConfigCmd.cmd = CONFIG_CMD_FLUSH;
    420         if (setType(&mConfigCmd, argv[2])) {
    421             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
    422             return 1;
    423         }
    424     } else if (strcmp(argv[1], "download") == 0) {
    425         int installCnt, uninstallCnt;
    426 
    427         if (argc != 2) {
    428             printf("Wrong arg number\n");
    429             return 1;
    430         }
    431         downloadNanohub();
    432         for (i = 0; i < MAX_DOWNLOAD_RETRIES; i++) {
    433             int updateCnt = parseConfigAppInfo(&installCnt, &uninstallCnt);
    434             if (updateCnt > 0) {
    435                 if (i == MAX_DOWNLOAD_RETRIES - 1) {
    436                     LOGE("Download failed after %d retries; erasing all apps "
    437                          "before final attempt", i);
    438                     eraseSharedArea();
    439                     uninstallCnt = 0;
    440                 }
    441                 removeApps(uninstallCnt);
    442                 downloadApps(installCnt);
    443                 resetHub();
    444             } else if (!updateCnt){
    445                 return 0;
    446             }
    447         }
    448 
    449         if (parseConfigAppInfo(&installCnt, &uninstallCnt) != 0) {
    450             LOGE("Failed to download all apps!");
    451         }
    452         return 1;
    453     } else {
    454         printf("Unsupported action: %s\n", argv[1]);
    455         return 1;
    456     }
    457 
    458     while (!fileWriteData("/dev/nanohub", &mConfigCmd, sizeof(mConfigCmd)))
    459         continue;
    460 
    461     if (drain) {
    462         signal(SIGINT, sig_handle);
    463         fd = open("/dev/nanohub", O_RDONLY);
    464         while (!stop) {
    465             (void) read(fd, buf, buf_size);
    466         }
    467         close(fd);
    468     }
    469     return 0;
    470 }
    471