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
setType(struct ConfigCmd * cmd,char * sensor)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
sig_handle(int sig)172 void sig_handle(__attribute__((unused)) int sig)
173 {
174 assert(sig == SIGINT);
175 printf("Terminating...\n");
176 stop = true;
177 }
178
openFile(const char * fname,const char * mode)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
parseInstalledAppInfo()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
findApp(uint64_t appId)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
parseConfigAppInfo(int * installCnt,int * uninstallCnt)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
fileWriteData(const char * fname,const void * data,size_t size)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
downloadNanohub()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
removeApps(int updateCnt)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
downloadApps(int updateCnt)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
eraseSharedArea()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
resetHub()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
main(int argc,char * argv[])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