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