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
setType(struct ConfigCmd * cmd,char * sensor)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
sig_handle(int sig)162 void sig_handle(__attribute__((unused)) int sig)
163 {
164 assert(sig == SIGINT);
165 printf("Terminating...\n");
166 stop = true;
167 }
168
openFile(const char * fname,const char * mode)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
parseInstalledAppInfo()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
findApp(uint64_t appId)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
parseConfigAppInfo()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
fileWriteData(const char * fname,const void * data,size_t size)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
downloadNanohub()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
downloadApps(int updateCnt)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
eraseSharedArea()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
resetHub()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
main(int argc,char * argv[])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