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