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