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